On 05/24/2011 12:06 PM, Sam Steingold wrote: >> * Eric Blake <roy...@erqung.pbz> [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 ebl...@redhat.com +1-801-349-2682 Libvirt virtualization library http://libvirt.org
signature.asc
Description: OpenPGP digital signature