Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Consider a multithreaded application that encounters an error while calling a system function. The strerror() function returns a human-readable error string given an error number. According to C99, Section 7.22.6.2 specifically states that strerror() is not required to avoid data races. Conventionally it could rely on a static array that maps error numbers to error strings, and that array might be accessible and modifiable by other threads.

Code Block
bgColor#FFCCCC
errno = 0;
FILE* fd = fopen( filename, "r");
if (fd == NULL) {
  char* errmsg = strerror(errno);
  printf("Could not open file because of %s\n", errmsg);
}

Note that 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

The compliant solution uses strerror_r(), which has the same functionality as strerror() but guarantees thread safety.

Code Block
bgColor#ccccff

errno = 0;
FILE* fd = fopen( filename, "r");
if (fd == NULL) {
  char errmsg[BUFSIZ];
  if (strerror_r( errno, errmsg, BUFSIZ) != 0) {
    /* handle error */
  }
  printf("Could not open file because of %s\n", errmsg);
}

Note that 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. Check your strerror_r() manpage to see which version is available on your system.

Risk Assessment

Race conditions caused by multiple threads invoking the same library function can lead to abnormal termination of the application, data integrity violations, or denial-of-service attack.

...