The unknown-conversion branch printed %m, positional arguments, the grouping
flag and modifiers in an unusual order as literal characters. Only characters
FreeBSD's vfprintf prints as themselves are now printed.
(cherry picked from commit 0106858d3d39f83eb2234a5f581d5bf5260521a0)
The Windows printf family threw on the q length modifier, the D, O and U
conversions, an unknown conversion character and a format ending in a percent
sign, where FreeBSD's vfprintf formats the first three and prints the unknown
character itself or stops at the end of the format.
(cherry picked from commit 0e3b2896d228c601cefc992b2895723188ebf0fa)
feof_unlocked, ferror_unlocked, getc_unlocked and putc_unlocked are macros
on macOS, so they are called without the global scope qualifier. The
remaining differences are the ones Darwin's headers and libSystem have:
- CLOCK_REALTIME_COARSE and st_mtim do not exist; the write mark uses
CLOCK_REALTIME and st_mtimespec.
- tm_zone is a non-const char*.
- __cxa_thread_atexit returns void, so the wrapper reports success.
- Darwin's stack protector reads __stack_chk_guard from libSystem; the
guard of the guest libc has the postfixed name, which receives the NID
of the original.
- APS5_EXPORT spells the symbols with the leading underscore of Mach-O.
- GuestArenaSetProtection and PosixProtection are built on macOS as on Linux.
- The fclose failure test fills /dev/full, which exists on Linux only.
exception_runtime relies on the Itanium unwinder of libc, which is not
registered on macOS (the host libc++abi is used), so its test is only
registered elsewhere.
FreeBSD 11.4 vsnprintf checks the size minus the terminator against INT_MAX
before formatting and, when it is larger, sets errno to EOVERFLOW, writes a
terminator to the buffer and returns EOF (lib/libc/stdio/vsnprintf.c:61-67).
The guest formatted into the buffer and returned the length.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
sscanf, vsscanf, sscanf_s and vsscanf_s threw on Linux for %ls, %lc, %l[, %S and %C, because glibc stores a 32-bit wchar_t per character into the guest's 16-bit buffer. ScanGuest, the per-directive scanner the _s forms already use, now scans those fields itself: the input is decoded as UTF-8, mirroring the narrow printf family's UTF-8 output, and each character is stored as one 16-bit unit, the width and the _s size counting characters; %ls skips leading white space and stops at the next, %l[ matches an ASCII scanset with ranges and negation, and a %lc field that meets the end of the input early keeps what it read, as FreeBSD's convert_wchar does. sscanf and vsscanf route a format with a wide conversion through ScanGuest and keep the host path otherwise. The UTF-8 decoding and scanset matching live in ScanWideField.cpp, which throws for input that is not UTF-8, a character outside the BMP, a scanset member outside ASCII and positional arguments next to a wide conversion; wide conversions in fscanf still throw.
The console's libSceLibcInternal.sprx (measured on firmware 12.70 in
#7549) prints %p as bare lowercase hex without a 0x prefix, prints 0 for
a null pointer, ignores #, + and the space flag, counts only the digits
towards the width, pads with spaces on the left (on the right for - and
with zeros for 0 when there is no precision), treats the precision as
the minimum number of digits, prints nothing for a null pointer under
%.0p, and accepts the l length. FormatPointer instead followed FreeBSD
and printed 0x..., which is what a title does not see on hardware.
FormatPointer now prints the digits alone, the narrow Windows formatter
accepts %lp, and Linux routes %p and %lp to the guest formatter instead
of glibc, which prints the FreeBSD form and (nil) for a null pointer.
The wide family still refuses %lp, because the console's swprintf was
not measured with it; it returns -1 as it does for any other conversion
the formatter rejects. The debt note records the pointer cases the
console was not measured with and what the Linux routing means for a
format that mixes %p with a refused conversion.
The guest formatter passed the flags of %o, %u, %x and %X to the host, and
MinGW's printf prefixes a space to %u when the space flag is set: "% u" of 5
gave " 5". C17 7.21.6.1 applies both flags to signed conversions only, and
FreeBSD 11.4 vfprintf clears the sign for every unsigned conversion (nosign).
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The guest formatter handed NaN to the host's snprintf, which prints
-nan for a negative NaN and +nan or " nan" with the + and space flags.
FreeBSD 11's vfprintf clears the sign of every NaN and prints nan (NAN
for the upper-case conversions), keeping the width and the - flag and
ignoring 0. The formatter now does the same for a, e, f and g and
their long double forms.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VZWLdTjf1S57iLgn2rcaFb
On Linux sscanf, vsscanf, fscanf and sscanf_s hand their conversions to
glibc. Since glibc 2.38, code built as GNU C++ calls the C23 entry
points (__isoc23_vsscanf, __isoc23_vfscanf, __isoc23_sscanf), whose %i
reads a 0b/0B binary prefix. On main,
sscanf("0b101 x", "%i%n%7s", &value, &end, rest) stores value 5 and
end 5 and leaves "x" for the %s; " -0B11" gives -3. TechnicalDebt
records this.
FreeBSD's %i knows only the 0 and 0x prefixes. FreeBSD 11.4
lib/libc/stdio/vfscanf.c, parseint, lines 345-353 and 371-380:
case '0':
if (base == 0) {
base = 8;
flags |= PFXOK;
}
...
/* letters ok iff hex */
case 'A': case 'B': case 'C':
case 'D': case 'E': case 'F':
case 'a': case 'b': case 'c':
case 'd': case 'e': case 'f':
/* no need to fix base here */
if (base <= 10)
break; /* not legal here */
so "0b101" stores 0, consumes the "0" and leaves "b101", as C17 does
and as the strtol family here already does.
With glibc the scanf family now calls __isoc99_vsscanf and
__isoc99_vfscanf, the entry points GNU C++ used before glibc 2.38
(exported since 2.7), which read %i without the binary prefix. Other
hosts keep std::vsscanf and std::vfscanf. The TechnicalDebt entry is
removed.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FreeBSD's printf formats %m as the message for the errno value at the
time of the call. On Linux a format with %m went to glibc, which looks
the number up in Linux's table, so guest errno values above 34 got
another error's text: with errno 35 (EAGAIN) "[%m]" printed
"[Resource deadlock avoided]" instead of "[Resource temporarily
unavailable]", and errno 63 (ENAMETOOLONG) printed "Out of streams
resources". On Windows, and on Linux when the format also had a wide
argument, the guest formatter threw on %m.
FreeBSD 11.4, lib/libc/stdio/vfprintf.c:
saved_errno = errno;
...
case 'm':
cp = strerror(saved_errno);
size = (prec >= 0) ? strnlen(cp, prec) : strlen(cp);
sign = '\0';
break;
The guest formatter now saves errno when it starts and formats %m as a
string with the guest strerror_r text, so width, precision and the -
flag apply as FreeBSD's string path applies them. On Linux a format with
%m goes to the guest formatter like one with a wide argument.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The guest formatter threw on %n$ and *m$, which FreeBSD's vfprintf and
glibc accept. It now reads the arguments a numbered format names into a
table first, with the types their conversions give them, and follows
FreeBSD's rules for unnumbered conversions and unnamed arguments.
FreeBSD's vfprintf takes ' as the thousands-grouping flag. The Windows
formatter threw on it as an unsupported conversion. The guest's setlocale
only accepts the C locale, which has no thousands separator, so the flag
changes nothing: it is dropped before the host's printf sees it, and the
host's locale cannot add separators.
C and FreeBSD's vfprintf print a single 0 when # meets octal zero with a
precision of 0. The Windows formatter passed the conversion to the host's
printf, which printed nothing; it now asks for one digit instead.
C17 7.21.6.2p16 returns EOF only if input fails before the first conversion completes, and a suppressed conversion completes. FreeBSD counts it in nconversions (vfscanf.c, releng/11.4, lines 799-805). The host scanf returned EOF there, so sscanf("12", "%*d%d", &v) reported EOF instead of 0. Each suppressed conversion now records its end with a %n and a result of EOF becomes 0 when one was recorded.
The Windows formatter passed %p to the host CRT, which prints 16
zero-padded digits without a prefix. FreeBSD prints 0x followed by the
lowercase hex digits (0x0 for a null pointer), as if by %#lx.
guest_formatting called sprintf with four variadic arguments and
libc_printf with one, all in registers, and did not call sscanf, so only
snprintf had a check that fails with the old Linux register rebuild. sprintf
now formats six integers, sscanf converts eight fields and libc_printf prints
seven integers; on the old code the first gives "1 2 3 4 0 0" and the other
two crash.
Checks suggested by nauroth in #1435.
guest_formatting_tests was built on Linux but registered with ctest on
Windows only, so the Linux printf and scanf exports had no coverage: on main
the test fails there at its first vsnprintf check and then crashes in
snprintf with eight integers.
It is registered on every platform now. The %ls checks stay Windows-only,
as glibc reads %ls as 32-bit wchar_t; that gap is recorded in TechnicalDebt.
libkernel:
- direct memory keeps its contents per physical page across unmap and
remap; a page mapped at two live addresses at once throws
- sceKernelDirectMemoryQuery answers from tracked allocations
- SCE protections read back as set, GPU and AMPR bits included
- APR prefix path resolve, file size and stat by id, positional reads,
fsync/pread/pwrite; directories open as descriptors on Windows
- sceKernelCheckReachability, getpeername, shutdown
- Dinkumware C11 threads (_Mtx_*, _Cnd_*, _Thrd_*) in the title libc
layout; any pthread stack size, rounded at thread creation
libc:
- unaddressed guest mappings go to the system-managed area from
0x2_0000_0000, leaving the application area to fixed mappings
- the process starts in /app0
- guest sscanf on Windows; a null %s prints as (null) as on FreeBSD
- localeconv, _FNan, _FDtest, _FExp, __udivti3, wcsncpy_s, aligned
operator new, _Throw_Cpp_error
Tests: direct memory following physical pages, guest formatting.
Co-Authored-By: Claude Opus 5.5 <[email protected]>