How to deal with getaddrinfo and thread-safety?

7.4k views Asked by At

I am using getaddrinfo for an IPv6-related C-project. The "man getaddrinfo" on my computer (uname -a: 3.5.0-23) only indicates that it is "reentrant". So I guess it is not thread-safe.

In scenarios where thread-safety is required, how to handle it? I also checked UNP but seems no concrete answer provided. Thanks a lot.

4

There are 4 answers

7
Remy Lebeau On BEST ANSWER

getaddrinfo() is indeed thread-safe. This is required by RFC 3493 Section 6.1:

Functions getaddrinfo() and freeaddrinfo() must be thread-safe.

On some platforms, gethostbyname() is thread-safe, but on others it is not. What gethostbyname() is not on all platforms is re-entrant. If you call gethostbyname() and then call gethostbyname() again in the same thread, the data from the first call is overwritten with data from the second call. This is because gethostbyname() usually uses a static buffer internally, that is why you have to copy the data before calling gethostbyname() again. getaddrinfo() does not suffer from that problem, as it allocates a new addrinfo struct every time it is called.

0
Andrew Selivanov On

Well, getaddrinfo is not quite thread safe on some platforms, Linux for example: http://man7.org/linux/man-pages/man3/getaddrinfo.3.html

   ┌────────────────┬───────────────┬────────────────────┐
   │Interface       │ Attribute     │ Value              │
   ├────────────────┼───────────────┼────────────────────┤
   │getaddrinfo()   │ Thread safety │ MT-Safe env locale │
   ├────────────────┼───────────────┼────────────────────┤
   │freeaddrinfo(), │ Thread safety │ MT-Safe            │
   │gai_strerror()  │               │                    │
   └────────────────┴───────────────┴────────────────────┘

Note env and locale attibutes:

Other safety remarks
   Additional keywords may be attached to functions, indicating features
   that do not make a function unsafe to call, but that may need to be
   taken into account in certain classes of programs:

   locale Functions annotated with locale as an MT-Safety issue read
          from the locale object without any form of synchronization.
          Functions annotated with locale called concurrently with
          locale changes may behave in ways that do not correspond to
          any of the locales active during their execution, but an
          unpredictable mix thereof.

          We do not mark these functions as MT-Unsafe, however, because
          functions that modify the locale object are marked with
          const:locale and regarded as unsafe.  Being unsafe, the latter
          are not to be called when multiple threads are running or
          asynchronous signals are enabled, and so the locale can be
          considered effectively constant in these contexts, which makes
          the former safe.

   env    Functions marked with env as an MT-Safety issue access the
          environment with getenv(3) or similar, without any guards to
          ensure safety in the presence of concurrent modifications.

          We do not mark these functions as MT-Unsafe, however, because
          functions that modify the environment are all marked with
          const:env and regarded as unsafe.  Being unsafe, the latter
          are not to be called when multiple threads are running or
          asynchronous signals are enabled, and so the environment can
          be considered effectively constant in these contexts, which
          makes the former safe.

So you will get random segfaults if not take it into account. See this old glibc bug discussion for details: https://sourceware.org/bugzilla/show_bug.cgi?id=13271

0
Mecki On

getaddrinfo() is part of the POSIX standard and the POSIX standard requires:

The freeaddrinfo() and getaddrinfo() functions shall be thread-safe.

Source: http://pubs.opengroup.org/onlinepubs/9699919799/functions/getaddrinfo.html

An OS may not claim to be POSIX conforming if that wasn't the case.

Operating systems officially POSIX conforming that you may have heard of:
AIX, BSD, IRIX, macOS, (Open)Solaris, QNX, as well as several others.
On these platforms you can rely upon getaddrinfo() being thread-safe.

Well known operating systems not officially POSIX conforming but always trying to stay as close to the POSIX standard as possible for software compatiblity:
BeOS, FreeBSD, GNU, iOS, Linux, NetBSD, OpenBSD, as well as several others.
On these platforms you cannot rely upon getaddrinfo() being entirely thread-safe but you can certainly expect it to be thread-safe enough so that you can use it from multiple threads in your application without having to wrap any locking around it.

Note that getaddrinfo() is also thread-safe on Linux as it will only become thread-unsafe if your code ever changes the locale or the environment while multiple threads are running and doing that is considered thread-unsafe on its own. So you can only make getaddrinfo() thread-unsafe if you do something that is forbidden anyway (well, it's not really forbidden but you do it at your own risk as it is not safe to do so).

Also note that even if the man page would not have said that (some POSIX man pages say nothing about thread-safety), the POSIX standard actually mandates:

3.407 Thread-Safe

A thread-safe function can be safely invoked concurrently with other calls to the same function, or with calls to any other thread-safe functions, by multiple threads. Each function defined in the System Interfaces volume of POSIX.1-2017 is thread-safe unless explicitly stated otherwise. Examples are any "pure" function, a function which holds a mutex locked while it is accessing static storage, or objects shared among threads.

Source: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html

0
Dan Anderson On

getaddrinfo() is thread safe. All (or almost all) function man pages have information on thread-safety. Reentrant means thread safe.