From 8b9529b99af3e7c87eef94d5268df92f6afe7743 Mon Sep 17 00:00:00 2001 From: screamm Date: Mon, 12 Oct 2026 13:16:38 +0200 Subject: [PATCH] fix(libScePosixForWebKit): keep the getservbyname result trivially destructible The per-thread servent storage held std::string and std::vector members, so getservbyname_nid_postfix registered a thread_local destructor through __cxa_thread_atexit. On Windows that destructor runs after emulated TLS freed the object, and prx_thread_local_destructors (#4029) rejects libScePosixForWebKit.prx for it. The result now lives in a thread_local struct of fixed-size char arrays and an alias pointer array, sized for the longest name (submission), alias (www-http), protocol (sctp) and alias count in the embedded table; static_asserts check the sizes against the table and that the struct is trivially destructible. The guest servent layout and the per-thread result FreeBSD's getservent.c keeps in its NSS TLS state are unchanged. Nothing is allocated, so the ENOMEM path is gone. Co-Authored-By: Claude Fable 5.1 --- .../prx/libScePosixForWebKit/Resolver.cpp | 62 +++++++++++++------ 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/core/libs/prx/libScePosixForWebKit/Resolver.cpp b/core/libs/prx/libScePosixForWebKit/Resolver.cpp index 9333e9c7e..0dd690183 100644 --- a/core/libs/prx/libScePosixForWebKit/Resolver.cpp +++ b/core/libs/prx/libScePosixForWebKit/Resolver.cpp @@ -10,12 +10,14 @@ #include "prx/libc/include/general/VabiMacros.hpp" #include "prx/libc/include/HostThreadLocal.hpp" #include +#include #include #include #include #include #include #include +#include #include #include "GuestResolver.hpp" @@ -58,13 +60,38 @@ constexpr ServiceRecord Services[]{ {"pop3s", 995, "tcp", {"spop3"}}, {"pop3s", 995, "udp", {"spop3"}}, }; +constexpr std::size_t ServiceNameSize = 11; +constexpr std::size_t ServiceAliasSize = 9; +constexpr std::size_t ServiceProtocolSize = 5; +constexpr std::size_t ServiceAliasCount = std::tuple_size_v; + +template +constexpr std::size_t LongestServiceText(TSelect select) { + std::size_t longest = 0; + for (const auto& service : Services) + for (const char* text : select(service)) + if (text) longest = std::max(longest, std::char_traits::length(text)); + return longest; +} + +static_assert(ServiceNameSize == LongestServiceText([](const ServiceRecord& record) { return std::array{record.name}; }) + 1); +static_assert(ServiceAliasSize == LongestServiceText([](const ServiceRecord& record) { return record.aliases; }) + 1); +static_assert(ServiceProtocolSize == LongestServiceText([](const ServiceRecord& record) { return std::array{record.protocol}; }) + 1); + struct ServiceLookup { - GuestResolver::ServiceEntry entry{}; - std::string name; - std::string protocol; - std::vector aliasNames; - std::vector aliases; + GuestResolver::ServiceEntry entry; + std::array name; + std::array protocol; + std::array, ServiceAliasCount> aliasNames; + std::array aliases; }; +static_assert(std::is_trivially_destructible_v); + +template +char* CopyServiceText(std::array& target, const char* text) { + std::memcpy(target.data(), text, std::strlen(text) + 1); + return target.data(); +} bool NumericAddress(const char* name, std::array& address) { std::array parts{}; @@ -196,22 +223,17 @@ GuestResolver::ServiceEntry* APS5_VABI getservbyname_nid_postfix(const char* nam for (const char* alias : service.aliases) named = named || (alias && std::strcmp(name, alias) == 0); if (!named || (protocol && std::strcmp(protocol, service.protocol) != 0)) continue; - try { - static thread_local ServiceLookup lookup; - lookup.name = service.name; - lookup.protocol = service.protocol; - lookup.aliasNames.clear(); - lookup.aliases.clear(); - for (const char* alias : service.aliases) - if (alias) lookup.aliasNames.emplace_back(alias); - for (auto& alias : lookup.aliasNames) lookup.aliases.push_back(alias.data()); - lookup.aliases.push_back(nullptr); - lookup.entry = {lookup.name.data(), lookup.aliases.data(), htons(service.port), lookup.protocol.data()}; - return &lookup.entry; - } catch (const std::bad_alloc&) { - errno = ENOMEM; - return nullptr; + static thread_local ServiceLookup lookup; + std::size_t count = 0; + for (const char* alias : service.aliases) { + if (!alias) continue; + lookup.aliases[count] = CopyServiceText(lookup.aliasNames[count], alias); + ++count; } + lookup.aliases[count] = nullptr; + lookup.entry = {CopyServiceText(lookup.name, service.name), lookup.aliases.data(), htons(service.port), + CopyServiceText(lookup.protocol, service.protocol)}; + return &lookup.entry; } return nullptr; }