...
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 (POSIX strerror_r()
)
This noncompliant code example compliant solution uses the POSIX strerror_r()
function, which has the same functionality as strerror()
but guarantees thread safety.
Code Block | ||||
---|---|---|---|---|
| ||||
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);
} |
While this code prevents a race window from being exploited within the strerror_r()
function itself, the fact that errno
is a static variable means there is still a race window between the fopen()
call and the beginning of the strerror_r()
call, in which another thread could modify errno
.
Compliant Solution (C99 mutex)
This compliant solution adds a mutex to protect the access of errno
by multiple threads.
Code Block | ||||
---|---|---|---|---|
| ||||
static pthread_mutex_t errno_mutex; int result; if ((result = pthread_mutex_lock(&errno_mutex)) == 0) { /* Handle error */ } 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); } if ((result = pthread_mutex_unlock(&errno_mutex)) == 0) { /* Handle error */ } |
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. You can get the XSI-compliant version if you compile applications in the way POSIX requires (that is, by defining _POSIX_C_SOURCE
or _XOPEN_SOURCE
appropriately). Check your strerror_r()
manual page to see which version(s) are available on your system.
...