Welcome to Software Development on Codidact!
Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.
Which functions in the C standard library must always be avoided?
It would seem that the C standard library is a collection of diverse functions that pretty much just ended up in the standard by tradition or "accident", rather than through some careful plan or rationale. During standardization of ANSI/ISO 9899:1990, they just grabbed a bunch of existing library functions in Unix and made them standard.
Some of them, like the notorious gets
are even broken by design. Clearly a lot of them were invented in a time long before things like software security or even compiler optimizations were invented. Or in case of the notorious strncpy
, from a time before null terminated strings were invented.
Is there a complete list of functions in the standard library that should always be avoided in any C program? Ideally covering ISO 9899:1990 to 202x versions of the language.
1 answer
The following users marked this post as Works for me:
User | Comment | Date |
---|---|---|
Lundin | (no comment) | Apr 5, 2022 at 14:17 |
Standard library functions that should never be used:
setjmp.h
-
setjmp()
Together with
longjmp()
, these functions are widely recogniced as incredibly dangerous to use: they lead to spaghetti programming, they come with numerous forms of undefined behavior, they can cause unintended side-effects in the program environment, such as affecting values stored on the stack. References: MISRA-C:2012 rule 21.4, CERT C MSC22-C. -
longjmp()
Seesetjmp()
.
stdio.h
-
gets()
The function has been removed from the C language (as per C11), as it was unsafe as per design. The function was already flagged as obsolete in C99. Usefgets()
instead. References: ISO 9899:2011 K.3.5.4.1, also see note 404).
stdlib.h
-
atoi()
family of functions.
These have no error handling but invoke undefined behavior whenever errors occur. Completely superfluous functions that can be replaced with thestrtol()
family of functions.strtol(src, NULL, 10)
is per definition 100% equivalent toatoi
except with well-defined error handling. References: ISO 9899:2018 7.22.1.2, MISRA-C:2012 rule 21.7.
string.h
-
strncat()
Has an awkward interface that are often misused. It is mostly a superfluous function. Also see remarks forstrncpy()
. -
strncpy()
The intention of this function was never to be a safer version ofstrcpy()
. Its sole purpose was always to handle an ancient string format on Unix systems, and that it got included in the standard library is a known mistake. This function is dangerous because it may leave the string without null termination and programmers are known to often use it incorrectly. References: Is strcpy dangerous and what should be used instead?
Standard library functions that should be used with caution:
assert.h
-
assert()
Comes with overhead and should generally not be used in production code. In production code, it is better to use an application-specific error handler which displays errors but does not necessarily close down the whole program.
ctype.h
-
For all functions in this header, note this vulnerabilities listed by the C standard ISO 9899:2018:
In all cases the argument is an
int
, the value of which shall be representable as an unsigned char or shall equal the value of the macroEOF
. If the argument has any other value, the behavior is undefined.Therefore passing a
char
which possibly contains negative values to the ctype.h functions is dangerous practice.
signal.h
-
signal()
Comes with various forms of poorly-defined behavior, particularly when called from within signal handlers.References: MISRA-C:2012 rule 21.5, CERT C SIG32-C.
stdarg.h
-
va_arg()
family of functions.
The presence of variable-length functions in a C program is almost always an indication of poor program design. Should be avoided unless you have very specific requirements.
stdio.h
-
Generally, this whole library is not recommended for production code, as it comes with numerous cases of poorly-defined behavior and poor type safety. References: MISRA-C:2012 rule 21.6.
Yours sincerely likes to name this one the worst programming library ever designed for any programming language, all categories, though of course that's subjective - I'm mostly basing this on monetary damage done to mankind.
-
fflush()
Perfectly fine to use for output streams. Invokes undefined behavior if used for input streams. -
gets_s()
Safe version ofgets()
included in C11 bounds-checking interface. It is preferred to usefgets()
instead, as per C standard recommendation. References: ISO 9899:2011 K.3.5.4.1. -
printf()
family of functions.
Poor performance functions that come with lots of undefined behavior and poor type safety.sprintf()
also has specific vulnerabilities. These functions should be avoided in production code. References: MISRA-C:2012 rule 21.6. -
scanf()
family of functions.
See remarks aboutprintf()
. Also, -scanf()
is vulnerable to buffer overruns if not used correctly.fgets()
is preferred to use when possible. References: CERT C INT05-C, MISRA-C:2012 rule 21.6. -
tmpfile()
family of functions.
Comes with various vulnerability issues. References: CERT C FIO21-C. -
feof()
The use of loops such aswhile(!feof(fp))
are almost certainly incorrect - instead the various file read functions used in the loop body should have their results checked directly. -
ungetc()
C17 7.31.11 Future language directions:The use of ungetc on a binary stream where the file position indicator is zero prior to the call is an obsolescent feature.
stdlib.h
-
malloc()
family of functions.
Perfectly fine to use in hosted systems, though be aware of well-known issues in C90 and therefore don't cast the result. Themalloc()
family of functions should never be used in freestanding applications.Also note that
realloc()
is dangerous in case you overwrite the old pointer with the result ofrealloc()
. In case the function fails, you create a leak.References: MISRA-C:2012 rule 21.3, Why should I not use dynamic memory allocation in embedded systems?
-
system()
Comes with lots of overhead and although portable, it is often better to use system-specific API functions instead. Comes with various poorly-defined behavior. References: CERT C ENV33-C.
string.h
-
strcat()
See remarks forstrcpy()
. -
strcpy()
Perfectly fine to use, unless the size of the data to be copied is unknown or larger than the destination buffer. If no check of the incoming data size is done, there may be buffer overruns. Which is no fault ofstrcpy()
itself, but of the calling application - thatstrcpy()
is unsafe is mostly a myth created by Microsoft. References: Is strcpy dangerous and what should be used instead? -
strtok()
Modifies the caller string and uses internal state variables, which could make it unsafe in a multi-threaded environment.
This post was originally written by me here. It has been updated here and with some links to Codidact content. I won't maintain the SO post any longer.
0 comment threads