On second thoughts, I guess it would make more sense to use the exact messages Windows' own implementation would return instead of whatever we had in the past (probably cribbed from some other OS or just made up?). I asked CI to spit those out[1]. Updated patch attached. Will add to CF.
[1] https://cirrus-ci.com/task/5816802207334400?logs=main#L15
From 490102fd52e20e67c4a862c1e889182328e115fa Mon Sep 17 00:00:00 2001 From: Thomas Munro <thomas.mu...@gmail.com> Date: Mon, 4 Dec 2023 14:52:57 +1300 Subject: [PATCH v2] Fix gai_strerror() thread-safety on Windows. Commit 5579388d removed code that supplied a fallback implementation of getaddrinfo(), which was dead code on modern systems. One tiny piece of the removed code was still doing something useful on Windows, though: that OS's own gai_strerror()/gai_strerrorA() function returns a pointer to a static buffer that it overwrites each time, so it's not thread-safe. In rare circumstances, a multi-threaded client program could get an incorrect or corrupted error message. Restore the replacement function, though now that it's only for Windows we can put it into a win32-specific file, cut it down to the errors that Windows documents and change the messages to match what the system gai_strerror() returns on that OS. Back-patch to 16. --- configure | 6 +++++ configure.ac | 1 + src/include/port/win32/sys/socket.h | 8 +++++++ src/port/meson.build | 1 + src/port/win32gai_strerror.c | 36 +++++++++++++++++++++++++++++ src/tools/msvc/Mkvcbuild.pm | 1 + 6 files changed, 53 insertions(+) create mode 100644 src/port/win32gai_strerror.c diff --git a/configure b/configure index 217704e9ca..1d4cd5caf3 100755 --- a/configure +++ b/configure @@ -16354,6 +16354,12 @@ esac ;; esac + case " $LIBOBJS " in + *" win32gai_strerror.$ac_objext "* ) ;; + *) LIBOBJS="$LIBOBJS win32gai_strerror.$ac_objext" + ;; +esac + case " $LIBOBJS " in *" win32getrusage.$ac_objext "* ) ;; *) LIBOBJS="$LIBOBJS win32getrusage.$ac_objext" diff --git a/configure.ac b/configure.ac index e49de9e4f0..a7a6b9a0ba 100644 --- a/configure.ac +++ b/configure.ac @@ -1878,6 +1878,7 @@ if test "$PORTNAME" = "win32"; then AC_LIBOBJ(win32env) AC_LIBOBJ(win32error) AC_LIBOBJ(win32fdatasync) + AC_LIBOBJ(win32gai_strerror) AC_LIBOBJ(win32getrusage) AC_LIBOBJ(win32link) AC_LIBOBJ(win32ntdll) diff --git a/src/include/port/win32/sys/socket.h b/src/include/port/win32/sys/socket.h index 0c32c0f7b2..f2b475df5e 100644 --- a/src/include/port/win32/sys/socket.h +++ b/src/include/port/win32/sys/socket.h @@ -23,4 +23,12 @@ #define ERROR PGERROR #endif +/* + * We don't use the Windows gai_strerror[A] function because it is not + * thread-safe. We define our own in src/port/win32gai_strerror.c. + */ +#undef gai_strerror + +extern const char *gai_strerror(int ecode); + #endif /* WIN32_SYS_SOCKET_H */ diff --git a/src/port/meson.build b/src/port/meson.build index 576a48b48c..c559c732e7 100644 --- a/src/port/meson.build +++ b/src/port/meson.build @@ -35,6 +35,7 @@ if host_system == 'windows' 'win32error.c', 'win32fdatasync.c', 'win32fseek.c', + 'win32gai_strerror.c', 'win32getrusage.c', 'win32link.c', 'win32ntdll.c', diff --git a/src/port/win32gai_strerror.c b/src/port/win32gai_strerror.c new file mode 100644 index 0000000000..f117831122 --- /dev/null +++ b/src/port/win32gai_strerror.c @@ -0,0 +1,36 @@ +#include <sys/socket.h> + +/* + * Windows has gai_strerrorA(), but it is not thread-safe. + * + * These are the documented error values and the messages returned by the + * system library (observed on Windows Server 2022), but our function returns + * pointers to string constants for thread-safety. + * + * https://learn.microsoft.com/en-us/windows/win32/api/ws2tcpip/nf-ws2tcpip-getaddrinfo + */ +const char * +gai_strerror(int errcode) +{ + switch (errcode) + { + case EAI_AGAIN: + return "This is usually a temporary error during hostname resolution and means that the local server did not receive a response from an authoritative server."; + case EAI_BADFLAGS: + return "An invalid argument was supplied."; + case EAI_FAIL: + return "A non-recoverable error occurred during a database lookup."; + case EAI_FAMILY: + return "An address incompatible with the requested protocol was used."; + case EAI_MEMORY: + return "Not enough memory resources are available to process this command."; + case EAI_NONAME: + return "No such host is known."; + case EAI_SERVICE: + return "The specified class was not found."; + case EAI_SOCKTYPE: + return "The support for the specified socket type does not exist in this address family."; + default: + return "Unknown server error"; + } +} diff --git a/src/tools/msvc/Mkvcbuild.pm b/src/tools/msvc/Mkvcbuild.pm index 46df01cc8d..c51296bdb6 100644 --- a/src/tools/msvc/Mkvcbuild.pm +++ b/src/tools/msvc/Mkvcbuild.pm @@ -113,6 +113,7 @@ sub mkvcbuild win32env.c win32error.c win32fdatasync.c win32fseek.c + win32gai_strerror.c win32getrusage.c win32gettimeofday.c win32link.c -- 2.43.0