This document proposes to prevent strictly conforming programs to use pointer values returned from certain library functions after the thread that originally called them has exited. It is related to papers N2225, N2226, N2227.
The core observation which motivates this document is that while the standard does not require to detect data races involving certain library functions, it does rule out a straightforward implementation of these library functions based on objects of thread storage duration. Returning a pointer to such objects does not work because the objects cease to exist once the thread exits.
The strerror
function is widely used in
thread-aware programs (which use threads and synchronization
in other ways). It is much simpler to use than
the strerror_r
function provided by some
implementations (whose use is further complicated by varying
prototypes between implementations).
Since reading the returned string happens after
the strerror
function has returned, merely
avoid data races within the function is insufficient. It
also would not address the higher-level race condition;
threads would still obtain an incorrect error message
generated by another thread.
As an alternative approach, an implementation could avoid
deallocating the object storing the error message when the
thread exits, and reuse it for a future call to
the strerror
function. However, that
introduces substantial complexity for a very small gain.
If an implementation does not include an unknown error
number in the result of the strerror
function
and takes some precautions about changing the program's
locale, a thread-safe implementation is already possible
because it is not necessary to provide backing storage for
the result: all possible result strings are known in advance
and can be precomputed.
POSIX defines both a strerror_r
and
a strerror_l
function. Both are required to be
thread-safe (but strerror_l
cannot be used with
the global locale handle, i.e., the program's locale).
There is no discussion what happens when the thread
calling strerror_l
exits; presumably the
previously returned pointer becomes invalid, as POSIX
mentions in the context of the setlocale
function.
The time conversion functions face a very similar issue.
Objects of thread storage duration are apparently already used in the Solaris implementation:
Theasctime()
,ctime()
,gmtime()
, andlocaltime()
functions are safe to use in multithread applications because they employ thread-specific data. [Source]
However, it is unclear whether this is at the expense of making undefined subsequent pointer access after thread exit.
POSIX suggests that a thread-safe implementation of these
functions is possible, but does not mention the behavior on
thread exit as far as the returned pointer is concerned
(which it does for the setlocale
function).
strerror
function), add:
TheIn J.2 (Undefined behavior), add:strerror
function returns a pointer to the string, the contents of which are locale- specific. The array pointed to shall not be modified by the program, but may be overwritten by a subsequent call to thestrerror
function. If the pointer is accessed after the thread which has called thestrerror
function has exited, the behavior is undefined.
— Access to the pointer returned by
the strerror
function after the thread that
originally called the function has exited (7.24.6.2).
Execution of any of the functions that return a pointer to one of these object types may overwrite the information in any object of the same type pointed to by the value returned from any previous call to any of them and the functions are not required to avoid data races with each other. 322) Accessing the returned pointer after the thread that called the function that returned it has exited results in undefined behavior. The implementation shall behave as if no other library functions call these functions.In J.2 (Undefined behavior), add:
— Access to the pointer returned by the time conversion functions after the thread that originally called the function returning it has exited (7.27.3).