strftime handed most conversions to the host's strftime, which differs
from FreeBSD 11's for E and O modifiers on conversions glibc does not
pair with them (%Ea was printed literally), padding flags on %+ and %v,
years outside 1000 to 9999 (%Y printed 899 and -1 where FreeBSD prints
0899 and -001), and out-of-range fields (%I of hour 100, %u of weekday
8). On Windows the padding flags printed nothing. strftime now follows
FreeBSD 11 strftime.c with the C locale on every host, and asctime
follows FreeBSD 11 asctime.c, padding years to four digits and setting
longer years apart.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
Dusklight (PPSA99305) imports atanhf (cPGyc5FGjy0) from
libSceLibcInternal.prx; the libc.prx it bundles only has a zero-return
stub for it.
The implementation follows the atanhf of the libc.prx bundled with
PPSA28319 (0x438a0), read from its disassembly: FreeBSD msun's
e_atanhf.c calling msun's s_log1pf.c, both as of 59bc2f09 (stable/9,
the revision the sinhf port took expm1f and expf from). The log1pf
paths for the positive arguments atanhf passes are inlined, as the
exported log1pf is still the host's. For |x| > 1, the infinities and
NaN, Sony's error helper raises FE_INVALID and sets errno to EDOM
before returning (x - x) / (x - x); for |x| = 1 it sets errno to
ERANGE before returning x / 0. Other arguments leave errno alone.
Running that code from the title's libc.prx on a Windows host gives
the same bits, errno and floating-point exceptions as the built
libc.prx for all 2^32 arguments, and msun's own e_atanhf.c and
s_log1pf.c built with the host compiler give the same bits. With the
host log1pf instead of the msun one, 4.7% of the arguments in [0, 1)
differ. guest_math pins bits for every branch reachable from atanhf,
both signs, and the errno and exception behaviour.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
PS5MC (PPSA99420) imports wcsftime (XbVXpf5WF28, aerolib) as the last
absent libSceLibcInternal import in its registry order (index 481), so
its predicted stop is:
FAIL: unresolved ELF import XbVXpf5WF28 from libSceLibcInternal.prx
The stop is predicted from the import order, not observed in a run.
wcsftime follows FreeBSD 11.4 lib/libc/locale/wcsftime.c (8c639945):
the wide format is converted with wcsrtombs, strftime fills a buffer of
maxsize * MB_CUR_MAX bytes limited to maxsize, and mbsrtowcs converts
the result back. A format unit that the single-byte C locale of
lib/libc/locale/none.c cannot encode returns 0 with EILSEQ, a maxsize
whose product with MB_CUR_MAX overflows returns 0 with EINVAL, and an
empty or overflowing result or a null buffer returns 0 with errno
unchanged; the ERANGE or EINVAL set by the Windows CRT's strftime is
discarded. A null format or tm throws, as FreeBSD dereferences it.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Homebrew built with the ps5-payload-dev SDK links LLVM libunwind
statically but imports _Unwind_Backtrace from libSceLibcInternal. Its
trace callback then reads each frame with its own _Unwind_GetIP, which
treats the context as a libunwind cursor and calls through the virtual
table in its first word. AnyPS5's context started with the saved RAX, so
the call jumped to a register value and the title crashed on its error
path (vkQuake, PPSA99010, without its game data). The context now starts
with a table in AbstractUnwindCursor's slot order that answers register
reads and writes, validFloatReg and isSignalFrame; other slots throw.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EvDbpwUPTa78oCAJqe7m9K
collate<char>::do_transform gave the result std::string a capacity of
exactly its length and threw for results of 4095 characters or more.
The console's libc.prx grows the string from its inline capacity of 15
to length | 15, so a 26-character result has capacity 31 and a 32-byte
allocation. Once capacity + 1 reaches 0x1000 bytes it takes the
over-aligned large allocation that the guest's inlined deallocation
expects: operator new(bytes + 0x27), the data aligned to 32 bytes and
the raw pointer stored just before it. This is the scheme of
Dinkumware's basic_string (_Newsize | _ALLOC_MASK) and of its
_Allocate in <xmemory0> (_BIG_ALLOCATION_THRESHOLD 4096,
_BIG_ALLOCATION_ALIGNMENT 32, _NON_USER_SIZE sizeof(void*) + 31),
including its bad_alloc when bytes + 0x27 would wrap.
do_transform now uses that capacity and allocation; the throw for long
results is gone. The debt entry in docs/dev/debt/libc.md now records
the capacity and large storage as unverified on hardware. guest_collate
checks the capacity and allocation size of a 26-character result, the
last small result (4079 characters, a 4080-byte block) and the first
large one (4080 characters, capacity 4095, a 4096 + 0x27-byte block
with the data aligned to 32 and the raw pointer before it). With main's
LocaleSupport.cpp it aborts at the allocation-size check of the
26-character result (lastSize 27 instead of 32).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Throw a guest std::system_error for the Dinkumware _Cpp_error codes,
as in VC12 and microsoft/STL thread0.cpp: the error_code holds the
FreeBSD errno and a guest generic error category modelled in libc, and
what() is the table message followed by the category message. Codes
outside the table throw std::out_of_range. The system_error copy
constructor and assignment now copy the error_code too.
Imported by Deathloop (PPSA01670) and Minecraft Legends (PPSA05510).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit bed1deafdee4b50bea9683a1cead0d0320150eb7)