Search code examples
clinuxthread-safetyglibcmanpage

Why is GNU GLIBC strsignal() considered thread unsafe on modern operating systems?


Background

First of all, I know the general reason strsignal() is not threading safe is the standard says it may not be. The strsignal() GNU C standard library function is defined in the POSIX.1-2008 specification, and in that specification it says:

The strsignal() function need not be thread-safe.

Link to specification https://pubs.opengroup.org/onlinepubs/9699919799.2016edition/functions/strsignal.html

Since the standard does not require strsignal() to be thread safe, code using this function can not assume it is thread safe, unless the specific implementation being used were to specify it was thread safe.

For example the POSIX.1-2008 spec says that strerror() may not be thread safe, but a change in glibc 2.32 means that in newer versions of glibc this function is now thread safe, and is listed as such on man 3 strerror.

https://lists.gnu.org/archive/html/info-gnu/2020-08/msg00002.html

Question

The manual page for the GNU linux version of the C standard library function for strsignal() specifies that this function is thread unsafe:

Linux man-pages 6.7

man 3 strsignal

┌───────────────────────────────┬───────────────┬─────────────────────────────────┐
│ Interface                     │ Attribute     │ Value                           │
├───────────────────────────────┼───────────────┼─────────────────────────────────┤
│ strsignal()                   │ Thread safety │ MT-Unsafe race:strsignal locale │
├───────────────────────────────┼───────────────┼─────────────────────────────────┤
│ sigdescr_np(), sigabbrev_np() │ Thread safety │ MT-Safe                         │
└───────────────────────────────┴───────────────┴─────────────────────────────────┘

However, a peek at the source code reveals that specifically for glibc shows that since 2.32 strsignal() has uses a thread local buffer, which I would think makes it thread safe.

https://elixir.bootlin.com/glibc/glibc-2.32/source/string/strsignal.c#L27

So, as of glibc 2.32, why is strerror() considered MT-Safe, but strsignal() is still documented here as MT-Unsafe?

The source code also reveals that there are no locale specific bindings for strsignal(), despite the documentation saying there is a possible locale thread race. Is this future proofing for changes that may be made in the future?

Update

The GLIBC commit that changed this behavior specifically says the change was made because the prior code was not thread safe.

https://github.com/bminor/glibc/commit/9deec7c8bab24659e78172dd850f4ca37c57940c#diff-0b727c8213dd076266c94142830b355d2ae281b0c7e246847a8558783ec6e242


Solution

  • First, you need to realize that GLIBC and man-pages are completely separate projects.

    The documentation may be incorrect or stale (patches welcome).

    Second, the fact that strsignal is using thread-local buffer does not itself guarantee thread-safety. Everything strsignal calls must also be thread-safe.

    The "race on locale" comment implies that

    • the output is affected by locale
    • which isn't thread-safe (involves global variables)