static __thread char buffer[18];
This makes the function thread-safe but this safety does not remove the need to worry about use within a single thread. Consider the following snippet of code:
#include <arpa/inet.h>
#include <stdio.h>
int main () {
struct in_addr a = { .s_addr = 1234567 }, b = { .s_addr = 7654321 };
return printf ("%s : %s\n", inet_ntoa (a), inet_ntoa (b));
}
Since inet_ntoa is used twice within the argument list the result is dependent on the order of evaluation of the arguments to printf. Regardless of which call gets evaluated first the output will always print the same IP address twice. On my system, the result is:
135.214.18.0 : 135.214.18.0
This is a result of two things: arguments are evaluated before their results are used by printf; and inet_ntoa overwrites static storage on each invocation. Looking at the instructions for this C code makes this clear:
.LC0:
.string "%s : %s\n"
.text
.globl main
.type main, @function
main:
pushl %ebp
movl %esp, %ebp
pushl %ebx
andl $-16, %esp
subl $32, %esp
movl $1234567, 24(%esp)
movl $7654321, 28(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call inet_ntoa
movl %eax, %ebx ; pointer stored to static memory
movl 24(%esp), %eax
movl %eax, (%esp)
call inet_ntoa
movl $.LC0, %edx
movl %ebx, 8(%esp) ; arg2 to printf; pointer from above
movl %eax, 4(%esp) ; arg1 to printf; new pointer, same static memory
movl %edx, (%esp) ; arg0 (format string)
call printf
movl -4(%ebp), %ebx
leave
ret
The correct way to call inet_ntoa consecutively is to save each result to a local variable.
#include <arpa/inet.h>
#include <string.h>
#include <stdio.h>
int main () {
struct in_addr a = { .s_addr = 1234567 }, b = { .s_addr = 7654321 };
char ipa[18] = { 0 }, ipb[18] = { 0 };
strcpy (ipa, inet_ntoa (a));
strcpy (ipb, inet_ntoa (b));
return printf ("%s : %s\n", ipa, ipb);
}