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.
This commit is contained in:
ayeteadoe 2025-08-29 09:27:41 -07:00 committed by Andrew Kaster
parent 643f0de422
commit 7683f1285f
Notes: github-actions[bot] 2025-10-30 03:09:04 +00:00
4 changed files with 60 additions and 18 deletions

View file

@ -1,5 +1,6 @@
/*
* Copyright (c) 2024, stasoid <stasoid@yahoo.com>
* Copyright (c) 2025, ayeteadoe <ayeteadoe@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -9,6 +10,7 @@
#pragma once
#include <AK/Assertions.h>
#include <AK/Platform.h>
#ifdef AK_OS_WINDOWS // needed for Swift
@ -18,4 +20,40 @@
# undef IN
# pragma comment(lib, "ws2_32.lib")
# include <io.h>
# include <stdlib.h>
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

View file

@ -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<int> open(StringView path, int options, mode_t mode)
{
ByteString str = path;

View file

@ -10,6 +10,9 @@
#include <LibMain/Main.h>
#include <string.h>
#include <time.h>
#if defined(AK_OS_WINDOWS)
# include <AK/Windows.h>
#endif
namespace Main {
@ -31,6 +34,10 @@ int main(int argc, char** argv)
{
tzset();
#if defined(AK_OS_WINDOWS)
windows_init();
#endif
Vector<StringView> 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);

View file

@ -8,6 +8,9 @@
#include <AK/Format.h>
#include <AK/Vector.h>
#include <LibTest/TestSuite.h>
#if defined(AK_OS_WINDOWS)
# include <AK/Windows.h>
#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<StringView> 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.