bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

strerror vs. threads [was: new files imported without new modules added]


From: Eric Blake
Subject: strerror vs. threads [was: new files imported without new modules added]
Date: Tue, 24 May 2011 12:24:34 -0600
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.17) Gecko/20110428 Fedora/3.1.10-1.fc14 Lightning/1.0b3pre Mnenhy/0.8.3 Thunderbird/3.1.10

On 05/24/2011 12:06 PM, Sam Steingold wrote:
>> * Eric Blake <address@hidden> [2011-05-24 10:54:20 -0600]:
>>
>> Are you multi-threaded?  Then you are suffering from a data race.
> 
> I am sorry, I am afraid I am out of my depth.
> Why is this function "suffering from a data race"?
> 
> const char *strerror (int e) {
>   switch (e) {
>     case EINPROGRESS: return "Operation now in progress";
>     case EALREADY: return "Operation already in progress";
>     ...
>   }
...
  {
    static char const fmt[] = "Unknown error (%d)";
    verify (sizeof (buf) >= sizeof (fmt) + INT_STRLEN_BOUND (n));
    sprintf (buf, fmt, n);

> }

Try:

strerror(-1) in thread 1
strerror(-2) in thread 2

POSIX explicitly allows strerror to use a static buffer, and that's
_exactly_ what gnulib's implementation does on out-of-range input.
Which means that "Unknown error (-1)" of thread 1 and "Unknown error
(-2)" of thread 2 are calling sprintf on the same memory at the same
time, and you will get indeterminate results.  And other implementations
might share a single buffer across threads even for in-range messages
(at least FreeBSD strerror() overwrites the contents at the pointer from
prior calls, rather than returning distinct pointers, when calling
strerror(EACCES); strerror(ERANGE) in the same thread, although I
haven't yet looked at BSD sources to see whether that is thread-local or
global storage).

Since POSIX explicitly documents that strerror() need not be threadsafe,
you should not use it in multi-threaded programs.  Just because glibc's
version happens to be threadsafe does not mean that all other
implementations are threadsafe.

strerror_l() is required to be thread-safe (that is, POSIX requires that
it use thread-local buffers for any computed values), but it is not as
widely implemented and not yet available in gnulib.

You only get true thread safety by passing in the storage, as is the
case of strerror_r.

-- 
Eric Blake   address@hidden    +1-801-349-2682
Libvirt virtualization library http://libvirt.org

Attachment: signature.asc
Description: OpenPGP digital signature


reply via email to

[Prev in Thread] Current Thread [Next in Thread]