Some C standard library functions are not guaranteed to be reentrant with respect to threads. Functions such as
asctime() return a pointer to the result stored in function-allocated memory on a per-process basis. Other functions such as
rand() store state information in function-allocated memory on a per-process basis. Multiple threads invoking the same function can cause concurrency problems, which often result in and can cause more serious vulnerabilities, such as abnormal termination, denial-of-service attack, and data integrity violations.
According to the C Standard, the library functions listed in the following table may contain data races when invoked by multiple threads.
|MSC30-C. Do not use the rand() function for generating pseudorandom numbers|
|ENV34-C. Do not store pointers returned by certain functions|
|Protect multithreaded access to locale-specific functions with a mutex|
|Do not attempt to initialize an atomic variable from multiple threads|
|Do not call with a null |
Section 2.9.1 of the Portable Operating System Interface (POSIX®), Base Specifications, Issue 7 [IEEE Std 1003.1:2013] extends the list of functions that are not required to be thread-safe.
Noncompliant Code Example
In this noncompliant code example, the function
f() is called from within a multithreaded application but encounters an error while calling a system function. The
strerror() function returns a human-readable error string given an error number. The C Standard, 188.8.131.52 [ISO/IEC 9899:2011], specifically states that
strerror() is not required to avoid data races. An implementation could write the error string into a static array and return a pointer to it, and that array might be accessible and modifiable by other threads.
This code first sets
errno to 0 to comply with ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only after the function returns a value indicating failure.
Compliant Solution (Annex K,
This compliant solution uses the
strerror_s() function from Annex K of the C Standard, which has the same functionality as
strerror() but guarantees thread-safety:
Because Annex K is optional,
strerror_s() may not be available in all implementations.
Compliant Solution (POSIX,
This compliant solution uses the POSIX
strerror_r() function, which has the same functionality as
strerror() but guarantees thread safety:
Linux provides two versions of
strerror_r(), known as the XSI-compliant version and the GNU-specific version. This compliant solution assumes the XSI-compliant version, which is the default when an application is compiled as required by POSIX (that is, by defining
_XOPEN_SOURCE appropriately). The
strerror_r() manual page lists versions that are available on a particular system.
|Supported, but no explicit checker|
A module written in Compass/ROSE can detect violations of this rule
|LDRA tool suite|
|44 S||Partially Implemented|
Avoid using thread-unsafe functions
|CERT C: Rule CON33-C||Checks for data race through standard library function call (rule fully covered)|
Key here (explains table format and definitions)
|CERT C Secure Coding Standard||ERR30-C. Set errno to zero before calling a library function known to set errno, and check errno only after the function returns a value indicating failure||Prior to 2018-01-12: CERT: Unspecified Relationship|
|CERT C||CON00-CPP. Avoid assuming functions are thread safe unless otherwise specified||Prior to 2018-01-12: CERT: Unspecified Relationship|
|CWE 2.11||CWE-330||2017-06-28: CERT: Partial overlap|
|CWE 2.11||CWE-377||2017-06-28: CERT: Partial overlap|
|CWE 2.11||CWE-676||2017-05-18: CERT: Rule subset of CWE|
CERT-CWE Mapping Notes
Key here for mapping notes
CWE-330 and CON33-C
Independent( MSC30-C, MSC32-C, CON33-C)
Intersection( CWE-330, CON33-C) =
- Use of rand() or srand() from multiple threads, introducing a race condition.
CWE-330 – CON33-C =
- Use of rand() or srand() without introducing race conditions
- Use of other dangerous functions
CON33-C – CWE-330 =
- Use of other global functions (besides rand() and srand()) introducing race conditions
CWE-377 and CON33-C
Intersection( CWE-377, CON33-C) =
- Use of tmpnam() from multiple threads, introducing a race condition.
CWE-377 – CON33-C =
- Insecure usage of tmpnam() without introducing race conditions
- Insecure usage of other functions for creating temporary files (see CERT recommendation FIO21-C for details)
CON33-C – CWE-377 =
- Use of other global functions (besides tmpnam()) introducing race conditions
CWE-676 and CON33-C
- Independent( ENV33-C, CON33-C, STR31-C, EXP33-C, MSC30-C, ERR34-C)
- CON33-C lists standard C library functions that manipulate global data (e.g., locale()), that can be dangerous to use in a multithreaded context.
- CWE-676 = Union( CON33-C, list) where list =
- Invocation of the following functions without introducing a race condition:
- rand(), srand(, getenv(), getenv_s(), strtok(), strerror(), asctime(), ctime(), localtime(), gmtime(), setlocale(), ATOMIC_VAR_INIT, atomic_init(), tmpnam(), mbrtoc16(), c16rtomb(), mbrtoc32(), c32rtomb()
- Invocation of other dangerous functions
|[IEEE Std 1003.1:2013]||Section 2.9.1, "Thread Safety"|
Subclause 184.108.40.206, "The
|[Open Group 1997b]||Section 10.12, "Thread-Safe POSIX.1 and C-Language Functions"|