- strtol, strtoul, strtoll, strtoull and strtouq return 0 for a base
outside 0 and 2 to 36, leave the end at the start and set EINVAL;
strtoimax, strtoumax, _Stoull, _Stoul and the wide forms do the same
without errno.
- A 0x prefix with no hexadecimal digit after it (base 0 or 16) is no
conversion: the end stays at the start of the string.
- wcstol, wcstoll and wcstoimax take one sign, convert the rest with
wcstoull and clamp to the signed range with ERANGE, so "- 1" is -1
and "+\t-1" overflows.
- atoi, atol and atoll truncate strtoull's result.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RbLgECLQ2bpDM7oe2urGZK
strrchr passed its int argument to the host strrchr unchanged. On Windows the
host compares it with the signed char bytes of the string, so a byte of 0x80 to
0xFF passed as an unsigned value (0xE9) or a value above 255 (0x12F) was not
found, where FreeBSD converts the argument to char first.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
macOS's strtoll and strtoull set errno to EINVAL when the subject has
no digits, as in "", "words" or " +". The guest's integer conversions
pass that to the title, while guest_atoi, guest_wide_conversion and
guest_math expect errno unchanged, as glibc leaves it. So atoi("")
returned 0 with errno 22 on macOS, and all three tests failed there.
A ParseInteger helper in SonyCrt.hpp calls the host's conversion and,
on macOS, restores the caller's errno when nothing was converted and
the base is valid. An overflow still sets ERANGE, and an invalid base
still sets EINVAL. strtol, strtoul, strtoll, strtoull, atoi, atol,
atoll, _Stoull and the wcsto* integer conversions in Strings.cpp use
it. On other hosts the helper calls the conversion unchanged.
In a payload process on a PS5 (firmware 12.70), the strtod and wcstod
of libSceLibcInternal.sprx keep the payload of a NAN(...) sequence,
read as FreeBSD 11's gdtoa hexnan reads it, under the quiet bit and
with the sign. strtof, wcstof, strtold and wcstold return the positive
default quiet NaN whatever the sign and the sequence, and consume a
sequence of letters, digits and underscores up to its closing
parenthesis. Here every NaN lost its payload, and strtof and strtold
kept the sign.
The model reproduces the 64 NaN inputs that p11, p14, p27 and p33
measured, including blanks and other characters inside the parentheses
and unterminated sequences, and the test now pins them. It also pins
two p71 cases measured through strtod: nan(1 2), and "nan( " followed
by NUL and ")". In hexnan, a blank after a payload digit, while a
32-bit word of the payload is still free, starts a blank skip that has
no NUL check, so when only blanks follow up to the terminating NUL the
console reads past it (p71); that case throws here. A blank right after
"nan(" is skipped with a NUL check, and the console stopped at the NUL
there.
AI-assisted: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
C17 7.22.1.3 and 7.29.4.1.1 interpret NAN(n-char-sequence) as a quiet
NaN. With MinGW-w64, std::strtod, strtof and strtold are mingw-w64's
gdtoa functions, which copy the hex digits into the significand
without the quiet bit, and for long double without the x87 integer
bit: strtod("nan(0x123)") returned the signaling NaN
0x7ff0000000000123 and strtold a pseudo-NaN. A payload whose only set
bit is the implicit or x87 integer bit gave infinity:
strtof("nan(0x800000)"), strtod("nan(0x10000000000000)") and
strtold("nan(0x8000000000000000)") returned +inf. glibc returns quiet
NaNs that keep the payload.
C17 7.12.11.2p2 makes nan("n-char-sequence") equivalent to
strtod("NAN(n-char-sequence)", NULL), and nan and nanf already return
the console's fixed quiet NaNs, ignoring the tag. ParseFloat, which
strtod, strtof, strtold, atof and the wide variants share, now returns
the same values, 0x7ff8000000000000 and 0x7fc00000, negated after a
minus sign, on Windows and Linux. strtold returns the x87 default
quiet NaN, since no console nanl was observed.
FreeBSD returns the difference of the lowercased bytes where the strings
differ, including where one of them ends. The guest wrappers returned the raw
difference of the terminator and the unfolded byte, so strcasecmp("ab", "A")
gave 66 instead of 98.
PS5MC (PPSA99420) stops at start-up on wcstok once sendfile is in. It
follows FreeBSD's three-argument wcstok over the guest's 16-bit wchar_t:
leading delimiters are skipped, the token ends at the next delimiter,
which is overwritten with 0, and *last is set to null when the string
runs out.
FreeBSD's memset_s returns EINVAL for every constraint violation and writes nothing when smax or n exceeds RSIZE_MAX. The guest returned ERANGE when n exceeded smax and wrote up to min(n, smax) bytes even when smax or n exceeded RSIZE_MAX.
(cherry picked from commit bf08837cf929e40f1b646df82e140a33076d5587)
Both parse like strtol and strtoll in base 10. The guest long is 64
bits wide on every host, so atol uses strtoll rather than the host
atol, whose long is 32 bits on Windows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wcstol, wcstoll, wcstoul and wcstoull parse the ASCII prefix of the
guest's UTF-16 text with std::strtoll and std::strtoull, which glibc 2.38
and later bind to the C23 __isoc23_* functions: wcstol(u"0b101", &end, 0)
returned 5 with the end pointer after the whole string. They now check
StopAtBinaryPrefix_nid_no_patch first, like the narrow functions, and the
end pointer maps back through ParseAsciiPrefix as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
C17 has no binary prefix: with base 0 or 2, strtol("0b101", &end, base)
reads the subject "0", returns 0 and leaves end at the 'b'. With glibc
2.38 or later, g++ (which defines _GNU_SOURCE) binds std::strtoll,
strtoull, strtoul, strtoimax and strtoumax to the C23 __isoc23_*
functions, which accept 0b/0B: the Linux exports returned 5 and
consumed the whole string. The Windows UCRT already follows C17, so the
same guest call gave different results on the two hosts.
strtol, strtoul, strtoll, strtoull, _Stoull, strtoimax, strtoumax and
_Stoul now return 0 with the end pointer after the '0' when, after
white space and an optional sign, the text starts with 0b or 0B and a
binary digit, in base 0 or 2. Everything else still goes to the host
function. The scanf family's %i has the same glibc behaviour; it is
recorded in TechnicalDebt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
wcstod, wcstof, wcstold, wcstol, wcstoll, wcstoul, wcstoull, wcscoll and wcsxfrm still forwarded to the host's wchar_t functions, which use 32-bit units on Linux. The wcsto* functions now parse the ASCII prefix of the guest string with the narrow parsers, as the C locale accepts only ASCII white space and digits. wcscoll compares like wcscmp and wcsxfrm copies, as strcoll and strxfrm do in the C locale.