For some features that make functions unsafe to call in certain contexts, there are known ways to avoid the safety problem other than refraining from calling the function altogether. The keywords that follow refer to such features, and each of their definitions indicate how the whole program needs to be constrained in order to remove the safety problem indicated by the keyword. Only when all the reasons that make a function unsafe are observed and addressed, by applying the documented constraints, does the function become safe to call in a context.
initFunctions marked with
initas an MT-Unsafe feature perform MT-Unsafe initialization when they are first called.
Calling such a function at least once in single-threaded mode removes this specific cause for the function to be regarded as MT-Unsafe. If no other cause for that remains, the function can then be safely called after other threads are started.
Functions marked with
init as an AS- or AC-Unsafe feature use the
libc_once machinery or similar to initialize internal
If a signal handler interrupts such an initializer, and calls any
function that also performs
libc_once initialization, it will
deadlock if the thread library has been loaded.
Furthermore, if an initializer is partially complete before it is canceled or interrupted by a signal whose handler requires the same initialization, some or all of the initialization may be performed more than once, leaking resources or even resulting in corrupt internal data.
Applications that need to call functions marked with
init as an
AS- or AC-Unsafe feature should ensure the initialization is performed
before configuring signal handlers or enabling cancellation, so that the
AS- and AC-Safety issues related with
libc_once do not arise.
raceFunctions annotated with
raceas an MT-Safety issue operate on objects in ways that may cause data races or similar forms of destructive interference out of concurrent execution. In some cases, the objects are passed to the functions by users; in others, they are used by the functions to return values to users; in others, they are not even exposed to users.
We consider access to objects passed as (indirect) arguments to
functions to be data race free. The assurance of data race free objects
is the caller's responsibility. We will not mark a function as
MT-Unsafe or AS-Unsafe if it misbehaves when users fail to take the
measures required by POSIX to avoid data races when dealing with such
objects. As a general rule, if a function is documented as reading from
an object passed (by reference) to it, or modifying it, users ought to
use memory synchronization primitives to avoid data races just as they
would should they perform the accesses themselves rather than by calling
the library function.
FILE streams are the exception to the
general rule, in that POSIX mandates the library to guard against data
races in many functions that manipulate objects of this specific opaque
type. We regard this as a convenience provided to users, rather than as
a general requirement whose expectations should extend to other types.
In order to remind users that guarding certain arguments is their
responsibility, we will annotate functions that take objects of certain
types as arguments. We draw the line for objects passed by users as
follows: objects whose types are exposed to users, and that users are
expected to access directly, such as memory buffers, strings, and
struct types, do not give reason for
functions to be annotated with
race. It would be noisy and
redundant with the general requirement, and not many would be surprised
by the library's lack of internal guards when accessing objects that can
be accessed directly by users.
As for objects that are opaque or opaque-like, in that they are to be
manipulated only by passing them to library functions (e.g.,
iconv_t), there might be
additional expectations as to internal coordination of access by the
library. We will annotate, with
race followed by a colon and the
argument name, functions that take such objects but that do not take
care of synchronizing access to them by default. For example,
unlocked functions will be annotated, but
those that perform implicit locking on
FILE streams by default
will not, even though the implicit locking may be disabled on a
In either case, we will not regard as MT-Unsafe functions that may access user-supplied objects in unsafe ways should users fail to ensure the accesses are well defined. The notion prevails that users are expected to safeguard against data races any user-supplied objects that the library accesses on their behalf.
This user responsibility does not apply, however, to objects controlled
by the library itself, such as internal objects and static buffers used
to return values from certain calls. When the library doesn't guard
them against concurrent uses, these cases are regarded as MT-Unsafe and
AS-Unsafe (although the
race mark under AS-Unsafe will be omitted
as redundant with the one under MT-Unsafe). As in the case of
user-exposed objects, the mark may be followed by a colon and an
identifier. The identifier groups all functions that operate on a
certain unguarded object; users may avoid the MT-Safety issues related
with unguarded concurrent access to such internal objects by creating a
non-recursive mutex related with the identifier, and always holding the
mutex when calling any function marked as racy on that identifier, as
they would have to should the identifier be an object under user
control. The non-recursive mutex avoids the MT-Safety issue, but it
trades one AS-Safety issue for another, so use in asynchronous signals
When the identifier relates to a static buffer used to hold return
values, the mutex must be held for as long as the buffer remains in use
by the caller. Many functions that return pointers to static buffers
offer reentrant variants that store return values in caller-supplied
buffers instead. In some cases, such as
tmpname, the variant is
chosen not by calling an alternate entry point, but by passing a
NULL pointer to the buffer in which the returned values are
to be stored. These variants are generally preferable in multi-threaded
programs, although some of them are not MT-Safe because of other
internal buffers, also documented with
constFunctions marked with
constas an MT-Safety issue non-atomically modify internal objects that are better regarded as constant, because a substantial portion of the GNU C Library accesses them without synchronization. Unlike
race, that causes both readers and writers of internal objects to be regarded as MT-Unsafe and AS-Unsafe, this mark is applied to writers only. Writers remain equally MT- and AS-Unsafe to call, but the then-mandatory constness of objects they modify enables readers to be regarded as MT-Safe and AS-Safe (as long as no other reasons for them to be unsafe remain), since the lack of synchronization is not a problem when the objects are effectively constant.
The identifier that follows the
const mark will appear by itself
as a safety note in readers. Programs that wish to work around this
safety issue, so as to call writers, may use a non-recursve
rwlock associated with the identifier, and guard all calls
to functions marked with
const followed by the identifier with a
write lock, and all calls to functions marked with the identifier
by itself with a read lock. The non-recursive locking removes the
MT-Safety problem, but it trades one AS-Safety problem for another, so
use in asynchronous signals remains undefined.
sigFunctions marked with
sigas a MT-Safety issue (that implies an identical AS-Safety issue, omitted for brevity) may temporarily install a signal handler for internal purposes, which may interfere with other uses of the signal, identified after a colon.
This safety problem can be worked around by ensuring that no other uses of the signal will take place for the duration of the call. Holding a non-recursive mutex while calling all functions that use the same temporary signal; blocking that signal before the call and resetting its handler afterwards is recommended.
There is no safe way to guarantee the original signal handler is restored in case of asynchronous cancellation, therefore so-marked functions are also AC-Unsafe.
Besides the measures recommended to work around the MT- and AS-Safety problem, in order to avert the cancellation problem, disabling asynchronous cancellation and installing a cleanup handler to restore the signal to the desired state and to release the mutex are recommended.
termFunctions marked with
termas an MT-Safety issue may change the terminal settings in the recommended way, namely: call
tcgetattr, modify some flags, and then call
tcsetattr; this creates a window in which changes made by other threads are lost. Thus, functions marked with
termare MT-Unsafe. The same window enables changes made by asynchronous signals to be lost. These functions are also AS-Unsafe, but the corresponding mark is omitted as redundant.
It is thus advisable for applications using the terminal to avoid
concurrent and reentrant interactions with it, by not using it in signal
handlers or blocking signals that might use it, and holding a lock while
calling these functions and interacting with the terminal. This lock
should also be used for mutual exclusion with functions marked with
race:tcattr(fd), where fd is a file descriptor for
the controlling terminal. The caller may use a single mutex for
simplicity, or use one mutex per terminal, even if referenced by
different file descriptors.
Functions marked with
term as an AC-Safety issue are supposed to
restore terminal settings to their original state, after temporarily
changing them, but they may fail to do so if cancelled.
Besides the measures recommended to work around the MT- and AS-Safety problem, in order to avert the cancellation problem, disabling asynchronous cancellation and installing a cleanup handler to restore the terminal settings to the original state and to release the mutex are recommended.