GC.malloc
resets WinError.value
on MinGW-w64
#15496
Labels
kind:bug
A bug in the code. Does not apply to documentation, specs, etc.
platform:windows-gnu
Windows support based on the MinGW-w64 toolchain + MSYS2
topic:stdlib:runtime
The following seemingly innocuous code:
prints
WinError::ERROR_INVALID_PARAMETER
for MSVC, butWinError::ERROR_SUCCESS
for MinGW-w64. The reason is rather subtle:USE_WIN32_SPECIFIC
orUSE_WIN32_COMPILER_TLS
for GNU and MSVC respectively.__declspec(thread)
, and for GNU it uses the internalGC_getspecific
, which is a macro for the Win32TlsGetValue
.TlsGetValue
is one of the few Win32 functions that always set a thread's last error, even if it succeeded.GC_malloc
orGC_malloc_atomic
ultimately accesses TLS.Few allocations look as straightforward as the code above. Here is one:
crystal/src/crystal/system/win32/socket.cr
Lines 169 to 173 in 181196f
WSAGetLastError
andGetLastError
are identical, except for their return types. Since this string interpolation allocates memory before the body ofSystemError::ClassMethods#from_wsa_error
callsWinError.wsa_value
, the error message will always be "The operation completed successfully.".One might argue that this is sensible behavior, in that
Errno.value
shares the same caveat with respect to C functions. But while functions in POSIX or the C standard library, includingmalloc
, may write positive integers toerrno
regardless of whether a failure occurred, they never write 0. Indeed, if the top snippet prints neitherERROR_INVALID_PARAMETER
norERROR_SUCCESS
, then a genuine error might have happened somewhere else.ERROR_SUCCESS
falls out of this natural expectation.We could work around this by defining an appropriate
Socket::Error.build_message
, but I wonder if there is a better solution for the general case, other than preservingWinError.value
on every single dynamic allocation.The text was updated successfully, but these errors were encountered: