From 7683f1285f562309437cbae7289a1c5e88241a5f Mon Sep 17 00:00:00 2001 From: ayeteadoe Date: Fri, 29 Aug 2025 09:27:41 -0700 Subject: [PATCH] AK: Expose helpers to invoke Windows runtime config directly in main() When shutting down helper processes, PosixSocketHelper::close() in SocketWindows when trying to close the socket fd with WSANOTINITIALISED. This was due to us initiating WinSock2 during static initialization and presumably also not terminating WinSock2 properly. Similar to WinSock2 initiation, calling CRT during static initialization is considered dangerous given the CRT DLL itself may not yet be initialized. Because of the above, we move to perform this Windows-specific runtime setup/teardown calls into the main() functions. --- AK/Windows.h | 38 +++++++++++++++++++++++++++++ Libraries/LibCore/SystemWindows.cpp | 18 -------------- Libraries/LibMain/Main.cpp | 12 +++++++++ Libraries/LibTest/TestMain.cpp | 10 ++++++++ 4 files changed, 60 insertions(+), 18 deletions(-) diff --git a/AK/Windows.h b/AK/Windows.h index bc5076b2a6..8778b89203 100644 --- a/AK/Windows.h +++ b/AK/Windows.h @@ -1,5 +1,6 @@ /* * Copyright (c) 2024, stasoid + * Copyright (c) 2025, ayeteadoe * * SPDX-License-Identifier: BSD-2-Clause */ @@ -9,6 +10,7 @@ #pragma once +#include #include #ifdef AK_OS_WINDOWS // needed for Swift @@ -18,4 +20,40 @@ # undef IN # pragma comment(lib, "ws2_32.lib") # include +# include + +inline void initiate_wsa() +{ + WSADATA wsa; + WORD version = MAKEWORD(2, 2); + int rc = WSAStartup(version, &wsa); + VERIFY(rc == 0 && wsa.wVersion == version); +} + +inline void terminate_wsa() +{ + int rc = WSACleanup(); + VERIFY(rc == 0); +} + +static void invalid_parameter_handler(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t) +{ +} + +inline void override_crt_invalid_parameter_handler() +{ + // Make _get_osfhandle return -1 instead of crashing on invalid fd in release (debug still __debugbreak's) + _set_invalid_parameter_handler(invalid_parameter_handler); +} + +inline void windows_init() +{ + initiate_wsa(); + override_crt_invalid_parameter_handler(); +} + +inline void windows_shutdown() +{ + terminate_wsa(); +} #endif diff --git a/Libraries/LibCore/SystemWindows.cpp b/Libraries/LibCore/SystemWindows.cpp index 7a0eda67b0..6d1e51f080 100644 --- a/Libraries/LibCore/SystemWindows.cpp +++ b/Libraries/LibCore/SystemWindows.cpp @@ -23,24 +23,6 @@ namespace Core::System { int windows_socketpair(SOCKET socks[2], int make_overlapped); -static void invalid_parameter_handler(wchar_t const*, wchar_t const*, wchar_t const*, unsigned int, uintptr_t) -{ -} - -static int init_crt_and_wsa() -{ - WSADATA wsa; - WORD version = MAKEWORD(2, 2); - int rc = WSAStartup(version, &wsa); - VERIFY(!rc && wsa.wVersion == version); - - // Make _get_osfhandle return -1 instead of crashing on invalid fd in release (debug still __debugbreak's) - _set_invalid_parameter_handler(invalid_parameter_handler); - return 0; -} - -static auto dummy = init_crt_and_wsa(); - ErrorOr open(StringView path, int options, mode_t mode) { ByteString str = path; diff --git a/Libraries/LibMain/Main.cpp b/Libraries/LibMain/Main.cpp index a9cc45ebcb..5410b178fd 100644 --- a/Libraries/LibMain/Main.cpp +++ b/Libraries/LibMain/Main.cpp @@ -10,6 +10,9 @@ #include #include #include +#if defined(AK_OS_WINDOWS) +# include +#endif namespace Main { @@ -31,6 +34,10 @@ int main(int argc, char** argv) { tzset(); +#if defined(AK_OS_WINDOWS) + windows_init(); +#endif + Vector arguments; arguments.ensure_capacity(argc); for (int i = 0; i < argc; ++i) @@ -41,6 +48,11 @@ int main(int argc, char** argv) .argv = argv, .strings = arguments.span(), }); + +#if defined(AK_OS_WINDOWS) + windows_shutdown(); +#endif + if (result.is_error()) { auto error = result.release_error(); warnln("\033[31;1mRuntime error\033[0m: {}", error); diff --git a/Libraries/LibTest/TestMain.cpp b/Libraries/LibTest/TestMain.cpp index 4c95faf0f5..ca9d1ad43a 100644 --- a/Libraries/LibTest/TestMain.cpp +++ b/Libraries/LibTest/TestMain.cpp @@ -8,6 +8,9 @@ #include #include #include +#if defined(AK_OS_WINDOWS) +# include +#endif #define TEST_MAIN main @@ -18,6 +21,10 @@ int TEST_MAIN(int argc, char** argv) return 1; } +#if defined(AK_OS_WINDOWS) + windows_init(); +#endif + Vector arguments; arguments.ensure_capacity(argc); for (auto i = 0; i < argc; ++i) @@ -25,6 +32,9 @@ int TEST_MAIN(int argc, char** argv) int ret = ::Test::TestSuite::the().main(argv[0], arguments); ::Test::TestSuite::release(); +#if defined(AK_OS_WINDOWS) + windows_shutdown(); +#endif // As TestSuite::main() returns the number of test cases that did not pass, // ret can be >=256 which cannot be returned as an exit status directly. // Return 0 if all of the test cases pass and return 1 otherwise.