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 <noreply@anthropic.com>
Implement getservbyname (H1bArJPagV0) in libScePosixForWebKit. Cloud
Play (PPSA99600) imports it from this library only (registry index 408,
call site 0x1042124); once fnmatch (#3545) is in, its predicted load
stop is:
FAIL: unresolved ELF import H1bArJPagV0 from libScePosixForWebKit.prx
The ps5-payload-dev SDK stubs (f5d40f02, sce_stubs/) declare
getservbyname in libScePosixForWebKit.c and not in libkernel.c or
libSceLibcInternal.c. The call site is the service-name branch of a
getaddrinfo inside the title: a non-numeric service is looked up with
protocol "tcp", "udp" or "sctp" and the port is read big-endian at
offset 16 of the result, which fixes the servent layout used here
(name, aliases, 32-bit port, protocol at 0, 8, 16, 24).
The guest has no /etc/services and the console's file is unknown, so the
function searches 37 lines of FreeBSD 11.4 etc/services (8c639945):
ftp-data, ftp, ssh, telnet, smtp, domain, tftp, http, pop3, ntp, imap,
https, rtsp, submission, imaps and pop3s with their aliases and
protocols, in file order. None of their names or aliases appears on an
earlier line of the full file, so these lookups answer as the full file
would. The search follows files_servent in lib/libc/net/getservent.c
(8c639945): exact, case-sensitive match on the name or an alias, a null
protocol takes the first match, the port in network byte order, the
result in per-thread storage like getserv's NSS TLS state. Any other
name returns null without touching errno, as for a name the file lacks.
The repository's getaddrinfo still resolves service names through the
host, so there was no table to share; this is recorded in
TechnicalDebt.md.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
libkernel numbered guest sockets from GuestSockets::FirstDescriptor
(0x10000000), so a title that puts a socket in a 1024-bit fd_set writes
fd / 8 bytes past it. The Epic Online Services SDK does this on its
RtcNetworkThread and three titles stop there (#1794):
Palworld PPSA23126 (queeeef, main a11c8f7f7):
FATAL: unhandled exception 0xc0000005 on thread 37164 'RtcNetworkThread'
rip 0x00007ffcdb1ea2be eossdk-ps5-shipping.prx.guest.prx+0xdea2be
rcx 0000000010000005 rsi 0000000000400000 r12 0000000010000005
The Mound PPSA26223 (xXPBSXx, main 0a8b1d32b):
FATAL: unhandled exception 0xc0000005 on thread 'RtcNetworkThread',
rip eossdk-ps5-shipping.prx.guest.prx+0xefc6f4, rcx = 0x10000005,
rsi = 0x400000
Dying Light 2 PPSA02262 (tv7):
FATAL: unhandled exception 0xc0000005 on thread 'RtcNetworkThread'
rcx 0000000010000005 ... rsi 0000000000400000 ... r12 0000000010000005
On FreeBSD 11.4 (8c639945) FD_SETSIZE is 1024 (sys/sys/select.h:58-59)
and sockets take the lowest free entry of the one process descriptor
table that files use (kern_descrip.c:1643-1660 fdalloc,
uipc_syscalls.c kern_socket through falloc).
Every socket number is now a real host descriptor: a zero-access NUL
handle registered with _open_osfhandle on Windows (as directory
descriptors already are) and an F_DUPFD_CLOEXEC duplicate of the host
socket on Linux. The socket table maps that number to the socket, so
"is this a socket" is a table lookup instead of a range check at the 31
former FirstDescriptor comparisons. close releases both the socket entry
and the number, dup and dup2 duplicate the number through the host table
and keep the socket shared, dup2 of a file onto a socket number drops the
socket entry, and sceKernelClose now closes sockets too. sceNetSocket and
sceNetAccept take their ids from the same table instead of a counter from
32, so libkernel and libSceNet numbers never collide.
select polls guest sockets alongside libSceNet sockets, the random device,
stdio and (on Linux) host descriptors; poll throws only for an open
descriptor that is not a guest socket and reports POLLNVAL otherwise.
File calls that used to fail with EBADF on the socket range return
FreeBSD's answer for a socket: lseek ESPIPE (kern_lseek), ftruncate and
getdirentries EINVAL (invfo_truncate, getvnode), flock EOPNOTSUPP;
fstat on a socket throws. pread on a closed descriptor returns EBADF.
title failing on host descriptor numbers; these three titles are that
case, and this change keeps host numbering for files and only moves
sockets into it.
Tests: guest_socket_descriptors (new: socket below 1024, select on a
socket and a file together, close frees the number for a file, dup of a
socket, sceKernelClose), guest_select (socket and pipe together, Linux),
guest_poll, guest_dup, guest_socket_pair, guest_fstatfs,
guest_posix_filesystem and guest_sce_net updated.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 20378375b31eb5db922db6e55f45e44a4dae6445)
* fix(agc): keep the driver's per-thread scratch out of thread_local teardown
With MinGW's emulated TLS, a thread_local with a destructor in a DLL is
destroyed after its storage is gone: when a std::thread ends, winpthread
runs libgcc's emutls key destructor, which frees the thread's thread_local
storage, and only then does the loader's DLL_THREAD_DETACH run the DLL's
tls_atexit list, so the destructors run on freed memory. The queue worker
touches four of them in libSceAgcDriver (the dispatch-ahead map, the
pending waits, the draw-snapshot compare vectors and the image decode
memo), and Driver::stop's join of the worker then corrupts the heap.
Under cdb's checking heap agc_driver_draw_cache_reuse stopped at the
worker's exit with heap corruption in all 127 runs, with graphics
pipeline libraries, with APS5_NO_PIPELINE_LTO=1 and with APS5_NO_GPL=1.
Without it the damage shows intermittently, as exit 0xc0000374 (2 of 143
runs with a cold NVIDIA shader cache) or as a fault in whatever allocates
next, such as NVIDIA's compiler on the optimized-link thread (#2980).
These objects now live in HostThreadLocal, fiber-local storage that owns
them, as the recorder's buffers do since e424b6b7b.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(libs): keep thread_local objects with destructors out of module teardown
The teardown order behind the driver's heap corruption holds in every
module: with MinGW's emulated TLS a thread's thread_local storage is freed
before the module's DLL_THREAD_DETACH runs its thread_local destructors,
so they run on freed objects. PreciseSleepUs's timer (used, among others,
by the video-out vblank thread) then closes a stale handle; libkernel's
directory path, socket waker and UUID random device, libSceRandom's random
device and libScePosixForWebKit's random device and host lookup free or
close stale objects. They move to HostThreadLocal. The other thread_locals
in the modules are trivially destructible or only built for Linux.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* test(libs): fail when a module registers a thread_local destructor
prx_thread_local_destructors lists the symbols of every built module and,
where MinGW's thread_local destructor support is linked in, disassembles
the module for calls to __cxa_thread_atexit outside libc's registration of
guest destructors. A module that keeps a thread_local with a destructor
fails it with the function that registers one: with main's libSceRandom
it reports sceRandomGetRandomNumber, and with this branch all 122 modules
pass, libc being the only one that links the support.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* fix(agc): keep the image memo behind its pointer
The image decode memo went into HostThreadLocal as the whole array. On
Linux, where HostThreadLocal is a plain thread_local, that put 1024 memo
entries into every thread's TLS block instead of one pointer. It keeps
its unique_ptr as before, now owned by HostThreadLocal, so Linux builds
the same thread_local as main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Dean Galvin <dean.galvin@live.com>
gai_strerror returned its own wording for most codes, so a resolver
failure was described with text FreeBSD's libc does not use: EAI_NONAME
(8) gave "Name or service not known" instead of "hostname nor servname
provided, or not known", EAI_BADFLAGS (3) "Invalid flags" instead of
"Invalid value for ai_flags", and an unknown code "Unknown address
resolution error" instead of "Unknown error". Twelve of the fifteen
texts differed.
FreeBSD 11.4, lib/libc/net/gai_strerror.c:
static const char *ai_errlist[] = {
"Success", /* 0 */
"Address family for hostname not supported", /* 1 */
"Temporary failure in name resolution", /* EAI_AGAIN */
"Invalid value for ai_flags", /* EAI_BADFLAGS */
"Non-recoverable failure in name resolution", /* EAI_FAIL */
"ai_family not supported", /* EAI_FAMILY */
"Memory allocation failure", /* EAI_MEMORY */
"No address associated with hostname", /* 7 */
"hostname nor servname provided, or not known", /* EAI_NONAME */
"servname not supported for ai_socktype", /* EAI_SERVICE */
"ai_socktype not supported", /* EAI_SOCKTYPE */
"System error returned in errno", /* EAI_SYSTEM */
"Invalid value for hints", /* EAI_BADHINTS */
"Resolved protocol is unknown", /* EAI_PROTOCOL */
"Argument buffer overflow" /* EAI_OVERFLOW */
};
...
if (ecode >= 0 && ecode < EAI_MAX)
return ai_errlist[ecode];
return "Unknown error";
The table and the unknown-code text now match, as 5830d8e44 did for
strerror.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
std::random_device in libstdc++ reads RDSEED on x86 Linux. On an AMD
EPYC 9V45 (Zen 5) CI runner its 32-bit results repeat about 130 times
in 65536 draws, so guest_posix_random fails. libc now exports
HostEntropy_nid_no_patch, which uses getentropy (rand_s on Windows) and
throws when the OS cannot provide entropy. arc4random, arc4random_buf,
sceRandomGetRandomNumber, /dev/random and /dev/urandom reads,
std::_Random_device and sceKernelUuidCreate use it, and the arc4random
and random device TechnicalDebt entries say so.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Implement arc4random (UISQ-dQzw28) in libScePosixForWebKit on top of the
existing arc4random_buf, so both draw from the same thread-local host
std::random_device. Like FreeBSD 11.4 lib/libc/gen/arc4random.c
(8c639945) it returns a uniformly distributed 32-bit value and has no
failure result.
Cloud Play (PPSA99600) imports it: the import audit in #3249 on main
ccf9ff90 lists `UISQ-dQzw28` `arc4random` among nine absent imports
("no PR or issue found"). The ps5-payload-dev SDK stubs (f5d40f02,
sce_stubs/libScePosixForWebKit.c) place arc4random, arc4random_buf and
fnmatch in libScePosixForWebKit; arc4random_uniform is in neither that
set nor libSceLibcInternal, so it is not added.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit 95da68017f6817abec785864e682530e9b135a2b)
Parse legacy decimal, octal and hexadecimal forms before host lookup. Preserve FreeBSD shorthand, whitespace and 64-bit accumulation, clear the SDK resolver error on numeric success, and add regression coverage.
Resolve the missing EVO-PLAYER import reported in #1578. Convert native host entries into the guest ABI with owned per-thread storage, and use the SDK network error location for failures.
Check numeric address bytes, guest hostent fields, per-thread result lifetime, and the SDK resolver error location. The check currently fails to link because the reported export is missing.
Every library CMakeLists.txt ended with the same block removing -static,
-static-libgcc and -static-libstdc++ from CMAKE_EXE_LINKER_FLAGS on MinGW,
because core/libs/CMakeLists.txt only removed them after adding the library
directories. Remove them before the libc and library directories are added
so each directory inherits the stripped flags, and drop the 52 copies.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017pTZqAyVSZy2FZmaqakPHZ