Do not use deprecated or obsolescent functions when more secure equivalent functions are available. Deprecated functions are defined by the C Standard. Obsolescent functions are defined by this recommendation.
Deprecated Functions
The gets()
function was deprecated by Technical Corrigendum 3 to C99 and eliminated from C11. The Annex K gets_s()
function is a recommended alternative to gets()
.
Obsolescent Functions
Functions in the first column of the following table are hereby defined to be obsolescent functions. To remediate invocations of obsolescent functions, an application might use inline coding that, in all respects, conforms to this guideline, or an alternative library that, in all respects, conforms to this guideline, or alternative non-obsolescent functions.
Obsolescent | Recommended | Rationale |
---|---|---|
|
| Non-reentrant |
|
| No error detection |
|
| No error detection |
|
| No error detection |
|
| No error detection |
|
| Non-reentrant |
|
| No exclusive access to file |
|
| No exclusive access to file |
|
| No error detection |
|
| No error detection |
The atof
, and ()
, atoi()
, atol()
atoll
functions are obsolescent because the ()
strtod
()
, strtof()
, strtol()
, strtold()
, strtoll()
, strtoul()
, and strtoull
functions can emulate their usage and have more robust error handling capabilities. See INT05-C. Do not use input functions to convert character data if they cannot handle all possible inputs.()
The fopen
and ()
freopen
functions are obsolescent because the ()
fopen_s
and ()
freopen_s
functions can emulate their usage and improve security by protecting the file from unauthorized access by setting its file protection and opening the file with exclusive access [ISO/IEC WG14 N1173].()
The setbuf
function is obsolescent because ()
setbuf
does not return a value and can be emulated using ()
setvbuf
. See ERR07-C. Prefer functions that support error checking over equivalent functions that don't.()
The rewind
function is obsolescent because ()
rewind
does not return a value and can be emulated using ()
fseek
. See ERR07-C. Prefer functions that support error checking over equivalent functions that don't.()
The asctime
and ()
ctime
functions are obsolescent because they use non-reentrant static buffers and can be emulated using ()
asctime_s
and ()
ctime_s
.()
Unchecked Obsolescent Functions
If you are using platforms that support Annex K, then functions in the first column of the following table are hereby defined to be obsolescent functions, with functions in the second column being the recommended alternatives from Annex K.
Obsolescent | Recommended |
---|---|
bsearch() | bsearch_s() |
fprintf() | fprintf_s() |
fscanf() | fscanf_s() |
fwprintf() | fwprintf_s() |
fwscanf() | fwscanf_s() |
getenv() | getenv_s() |
gmtime() | gmtime_s() |
localtime() | localtime_s() |
mbsrtowcs() | mbsrtowcs_s() |
mbstowcs() | mbstowcs_s() |
memcpy() | memcpy_s() |
memmove() | memmove_s() |
printf() | printf_s() |
qsort() | qsort_s() |
scanf() | scanf_s() |
snprintf() | snprintf_s() |
sprintf() | sprintf_s() |
sscanf() | sscanf_s() |
strcat() | strcat_s() |
strcpy() | strcpy_s() |
strerror() | strerror_s() |
strlen() | strnlen_s() |
strncat() | strncat_s() |
strncpy() | strncpy_s() |
strtok() | strtok_s() |
swprintf() | swprintf_s() |
swscanf() | swscanf_s() |
vfprintf() | vfprintf_s() |
vfscanf() | vfscanf_s() |
vfwprintf() | vfwprintf_s() |
vfwscanf() | vfwscanf_s() |
vprintf() | vprintf_s() |
vscanf() | vscanf_s() |
vsnprintf() | vsnprintf_s() |
vsprintf() | vsprintf_s() |
vsscanf() | vsscanf_s() |
vswprintf() | vswprintf_s() |
vswscanf() | vswscanf_s() |
vwprintf() | vwprintf_s() |
vwscanf() | vwscanf_s() |
wcrtomb() | wcrtomb_s() |
wcscat() | wcscat_s() |
wcscpy() | wcscpy_s() |
wcslen() | wcsnlen_s() |
wcsncat() | wcsncat_s() |
wcsncpy() | wcsncpy_s() |
wcsrtombs() | wcsrtombs_s() |
wcstok() | wcstok_s() |
wcstombs() | wcstombs_s() |
wctomb() | wctomb_s() |
wmemcpy() | wmemcpy_s() |
wmemmove() | wmemmove_s() |
wprintf() | wprintf_s() |
wscanf() | wscanf_s() |
For information on the tmpfile()
and tmpfile_s()
functions, see FIO21-C. Do not create temporary files in shared directories.
For information on the memset()
and memset_s()
functions, see MSC06-C. Beware of compiler optimizations.
To remediate invocations of obsolescent functions, an application might use any of the following recommended functions from ISO/IEC TR 24731-2, Extensions to the C Library—Part II: Dynamic Allocation Functions [ISO/IEC TR 24731-2]:
|
|
|
|
|
|
|
|
|
|
|
|
|
Noncompliant Code Example
In this noncompliant code example, the obsolescent functions strcat()
and strcpy()
are used:
#include <string.h> #include <stdio.h> enum { BUFSIZE = 32 }; void complain(const char *msg) { static const char prefix[] = "Error: "; static const char suffix[] = "\n"; char buf[BUFSIZE]; strcpy(buf, prefix); strcat(buf, msg); strcat(buf, suffix); fputs(buf, stderr); }
Compliant Solution
In this compliant solution, strcat()
and strcpy()
are replaced by strcat_s()
and strcpy_s()
:
#define __STDC_WANT_LIB_EXT1__ #include <string.h> #include <stdio.h> enum { BUFFERSIZE = 256 }; void complain(const char *msg) { static const char prefix[] = "Error: "; static const char suffix[] = "\n"; char buf[BUFFERSIZE]; strcpy_s(buf, BUFFERSIZE, prefix); strcat_s(buf, BUFFERSIZE, msg); strcat_s(buf, BUFFERSIZE, suffix); fputs(buf, stderr); }
Risk Assessment
The deprecated and obsolescent functions enumerated in this guideline are commonly associated with software vulnerabilities.
Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC24-C | High | Probable | Medium | P12 | L1 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Astrée | 24.04 | stdlib-use-ato stdlib-macro-ato stdlib-use-atoll stdlib-macro-atoll | Partially checked |
Axivion Bauhaus Suite | 7.2.0 | CertC-MSC24 | Fully implemented |
CodeSonar | 8.1p0 | BADFUNC.* | A number of CodeSonar's "Use of *" checks are for deprecated/obsolescent functions |
1.2 | CC2.MSC34 | Fully implemented | |
LDRA tool suite | 9.7.1 | 44 S | Fully implemented |
Parasoft C/C++test | 2023.1 | CERT_C-MSC24-a | The library functions atof, atoi and atol from library stdlib.h shall not be used |
PC-lint Plus | 1.4 | 586 | Fully supported |
Polyspace Bug Finder | R2024a | CERT C: Rec. MSC24-C | Checks for use of obsolete standard function (rec. fully covered) |
PVS-Studio | 7.33 | V513, V2001, V2002 | |
RuleChecker | 24.04 | stdlib-use-ato stdlib-macro-ato stdlib-use-atoll stdlib-macro-atoll | Partially checked |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C Secure Coding Standard | ERR07-C. Prefer functions that support error checking over equivalent functions that don't |
ISO/IEC TR 24772 | Use of Libraries [TRJ] |
MISRA C:2012 | Rule 21.3 (required) |
MITRE CWE | CWE-20, Insufficient input validation |
Bibliography
[Apple 2006] | Apple Secure Coding Guide, "Avoiding Race Conditions and Insecure File Operations" |
[Burch 2006] | Specifications for Managed Strings, Second Edition |
[Drepper 2006] | Section 2.2.1 "Identification When Opening" |
[IEEE Std 1003.1:2013] | XSH, System Interfaces, open |
ISO/IEC 23360-1:2006 | |
[ISO/IEC WG14 N1173] | Rationale for TR 24731 Extensions to the C Library Part I: Bounds-checking interfaces |
[Klein 2002] | "Bullet Proof Integer Input Using strtol() " |
[Linux 2008] | strtok(3) |
[Seacord 2013] | Chapter 2, "Strings" Chapter 8, "File I/O" |
[Seacord 2005b] | "Managed String Library for C, C/C++" |
19 Comments
Dhruv Mohindra
What happens when more secure equivalent functions are not available? Does this imply that legacy systems can continue to use deprecated functions?
Martin Sebor
It seems to me that we should either list the equivalent secure function for each of the obsolescent functions or show code that can achieve the corresponding effect. Without it, this rule is likely to be dismissed as impractical.
It's not clear to me that this is feasible for all the functions on the list. In particular, I'm not sure how to do that for
remove()
andrename()
neither of which appears to have a secure alternative in TR 24731 or a portable equivalent.I've expanded the table to list portable alternatives and secure equivalents.
David Svoboda
The remove() and rename() functions have no secure equivalents. Their inherent problem is that they operate on file names, allowing a TOCTOU race condition on file names.
Most other filename-related functions eliminate TOCTOU by replacement functions that operate on file descriptors...chmod() vs fchmod() for instance. (in POSIX). This is possible because chmod() manipulates information in the file's inode...if it has that, it doesn't need the name. The rename() and remove() functions need the file's name...the inode info won't cut it.
I think the current best advice is to go ahead & use remove() / rename() but only when in a secure directory...outside of a secure directory you can't prevent TOCTOU race conditions. I think we have other rules about these functions...if we don't, we should So I would agree those functions don't belong here.
David Svoboda
Why is strlen() not among the list of obsolescent functions?
Robert Seacord
This rule needs a ton of work, including compliant solutions.
Carol J. Lallier
Three of the Compliant Solutions in this rule do not have code examples.
David Svoboda
The mkostemp() function is a glibc extension, with pros and cons (but it is not standardized in POSIX). Creation of temporary files is thoroughly addressed in FIO43-C. Do not create temporary files in shared directories, and I'd rather not duplicate the wisdom of that rule here. I suggest we simply take out the NCCEs that deal with temporary files.
Roberto Bagnara
I agree David. Please take out or replace the NCCEs that you believe are redundant and I will see what remains to be done.
David Svoboda
I took out all the NCCEs except for the first one, as they are better demonstrated in rules specific to those functions.
Aaron Ballman
Would it make sense to list
strtok
andwcstok
under the list of obsolete functions due to their lack of re-entrancy? The_s
versions of those functions solve the problem.Is there meant to be a relationship between the top two tables in unchecked obsolete functions? I notice there are entries in the second table that do not have an analogy in the first (such as
abort_handler_s).
Robert Seacord
I have a pretty big question about abort_handler_s appearing in the second table as well. I would think that these tables should be combined, with the obsolete function on the left and the replacement function on the right.
Robert Seacord
I'm still confused as to why there are there are two categories of obsolescent functions. Shouldn't we combine them?
John Benito
Yes, I think the two tables should be combined, eliminating entries like abort_handler_s.
Aaron Ballman
I agree, they should be combined.
Joseph C. Sible
It seems a bit harsh to call functions "obsolescent" just because they have an Annex K replacement. Annex K is optional to implement, and since it was so poorly received, none of the mainstream Linux C libraries support it.
Fütő Gergely
During the implementation of this check in clang-tidy, a few things came up that I would like to share. Most of it is just reiteration of previous comments.
The two lists in 'Unchecked Obsolescent Functions' are inconsistent. Missing functions: tmpfile/tmpfile_s, tmpnam/tmpnam_s, memset/memset_s, scanf, strlen, wcslen. There are functions in the second list which are not replacement functions: abort_handler_s, set_constraint_handler_s, strerrorlen_s.
I think it would be much easier to comprehend the rule if there was only one list, containing the pairs unsafe function/replacement function, maybe the rationale.
Calling these functions obsolescent could be confusing. Maybe it would be better call them unsafe, with possible safe replacements in modern versions of C.
David Svoboda
Thank you for the feedback.
I revamped the table into an 'obsolescent functions' vs 'Annex K alternatives' as you suggest. I also added scanf & scanf_s to the table, their omission seems to have been an oversight. I also added strlen & wcslen, although their Annex K equivalents are slightly differently names. (Note that ISO C defines no strnlen or strlen_s or wcsnlen or wcslen_s functions).
At this point, "obsolescent functions" is not a standard term used by ISO C, so we can use it. While it is imperfect and vague, I don't see that vague-ness being resolved by calling these functions 'unsafe'. (IMO all functions are unsafe, some are just more unsafe than others :)
Joseph C. Sible
Why are asctime, ctime, fopen, and freopen still in the first table?
David Svoboda
Because I didn't change the first table; I only changed the second.