Add the missing wide secure formatting exports required by PPSA15552
(Dead Cells), whose load failed with `undefined symbol: Im55VJ-Bekc`:
swprintf_s and its va_list counterpart follow C11 Annex K.3.9.1.4
(the complete output, including the terminator, must fit), while
vsnwprintf_s is the va_list counterpart of snwprintf_s (K.3.9.1.3,
truncation with full length). The export names produce NIDs
Im55VJ-Bekc, oDoV9tyHTbA and 8SKVXgeK1wY respectively. Document
the new functions in docs/dev/debt/libc.md.
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>
The wide formatter behind swprintf, vswprintf, wprintf and snwprintf_s
does not know the ' (thousands grouping) flag: it takes ' for the
conversion and fails, so on main swprintf(buffer, 32, L"%'d", 1234567)
returns -1 with errno EINVAL and an empty buffer. The narrow guest
formatter accepts the flag since #3567.
FreeBSD 11.4 lib/libc/stdio/vfwprintf.c takes it as a flag
(lines 613-615):
case '\'':
flags |= GROUPING;
goto rflag;
and grouping_init (lines 129-147) adds separators only while
*gs->grouping != CHAR_MAX. In the C locale, the only one the guest's
setlocale accepts, lib/libc/locale/lnumeric.c (lines 44-50) has
static char numempty[] = { CHAR_MAX, '\0' };
...
"", /* thousands_sep */
numempty /* grouping */
so the flag prints the number unchanged. The wide formatter now skips
' with the other flags before it hands the conversion to the host's
snprintf, as the narrow one does.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The wide formatter behind swprintf, vswprintf, wprintf and snwprintf_s
does not parse %n$ or *m$. It reads the position digits as a field
width, takes '$' for the conversion and fails, so on main
swprintf(buffer, 32, L"%2$d-%1$d", 1, 2) returns -1 with errno EINVAL
and an empty buffer. Localized format strings that reorder their
arguments this way print nothing.
FreeBSD formats wide output with __vfwprintf (vswprintf.c line 79),
which takes positions exactly as the narrow vfprintf does. FreeBSD 11.4
lib/libc/stdio/vfwprintf.c lines 635-652:
case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
n = 0;
do {
n = 10 * n + to_digit(ch);
ch = *fmt++;
} while (is_digit(ch));
if (ch == '$') {
nextarg = n;
if (argtable == NULL) {
argtable = statargtable;
if (__find_warguments (fmt0, orgap,
&argtable)) {
and GETASTER (lines 509-531) reads a *m$ width or precision from
position m without moving nextarg.
The wide formatter now numbers its arguments with the narrow
formatter's NumberedArgumentClasses and ArgumentPosition, run over an
ASCII copy of the format, so the same FreeBSD rules apply: a position
selects the argument, *m$ does not move it, and a conversion without a
position takes the argument after the previous one. Formats without a
position are formatted as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Format through the shared wide formatter, truncate to the buffer and
return the full length, as C11 K.3.9.1.3 specifies. A null buffer or
format, a zero or oversized n, %n and a null %s argument are
runtime-constraint violations that return a negative value.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>