Repository navigation
Conversation
…a PS5 Measured on libSceLibcInternal.sprx of a PS5 on firmware 13.60: - snprintf_s and vsnprintf_s: RSIZE_MAX is 2^61 - 1. A null buffer, size 0 or a size above RSIZE_MAX returns -1 with the buffer untouched; a null format returns -1 with buffer[0] zeroed; %n or a null %s, %ls or %S argument returns -23, keeps the output written before it and zeroes buffer[0]. Every violation calls the constraint handler with the console's message, a null pointer and EINVAL. - sscanf_s and vsscanf_s: the size argument is 64 bits. A %s or %[ field of at least size characters stores its first size characters without a terminator and is a matching failure; %c stores at most size characters and succeeds. Null destinations and sizes above RSIZE_MAX call the handler and return the assignments, or -23 before any conversion. A literal mismatch at the end of input returns the assignments, and %n counts as a conversion for the EOF result. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.
Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.
|
|
Overlap coordination for a follow-up to #9321: I have a narrow wide-scanner patch for incomplete-exponent and literal-at-EOF behavior. Its code and tests are separate from this PR's measured formatting constraints, but both branches update the same libc debt bullet, which |
|
Thanks for checking. Making your follow-up depend on this PR and rebasing the debt bullet after it merges works for me. If this one is still waiting when yours is ready, go ahead first and I'll rebase the debt bullet here. |
|
@orezraey a merge-order note: #9479 (Windows |
|
Thanks for coordinating. #9479 going first works for me; once it merges I'll rebase this PR's test file over it, keeping both check functions and both calls in |
|
A data point for the The
What this means: sources disagree on whether the default handler ends the process. For a title that installs no handler, this bundled
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…les ship Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Thanks, that is a useful distinction. In 49903de the |
|
@JJenkx Thanks for the matrix. 4eaf64f makes |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
docs/dev/debt/libc.md: keep this branch's set_constraint_handler_s and swscanf_s text and take main's qsort/qsort_s split and _WStoul sentence (sentence-level 3-way merge, no sentence edited by both sides).
|
Hi orezraey, #9087 conflicts with main again, this time in core/libs/prx/libc/src/Formatting.cpp, and it can't be merged mechanically. #12468 rewrote the wide scanf conversions (%ls, %lc, %l[) to read through the scanner's |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
@oneandonlydean Done in 24f4242: current The wide path of the secure block is gone, since those conversions no longer reach it. |
|
Hi orezraey, Thanks for merging main earlier today. Since then #12428 (merged as Main now has the new unknown-conversion exit there: if (!std::strchr("diouxXaAeEfFgGcspn[SC", conversion)) return finish(assigned);and your branch inserts the Two other #12428 changes merge without conflicts but feed into your secure block, so please check them after the merge:
Length parsing also changed: it now accepts only one length letter, or a doubled core/libs/tests/Formatting.cpp and docs/dev/debt/libc.md merge without conflicts. Could you merge current main, keep the exit before the secure block and re-run the Formatting tests? Thanks. |
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Merged current
The six formatting and scan tests pass three runs in a row on Windows and Linux. A correction to my last reply: the Linux result I gave for |
What
snprintf_s,vsnprintf_s,sscanf_sandvsscanf_sfollowed C11 Annex K with guessed constants. Their debt entries said the constraint handler is not invoked and the console's values are unverified. In a payload process on a PS5 (firmware 13.60,libSceLibcInternal.sprx) most of those guesses differ.snprintf_s / vsnprintf_s (both behave the same;
errnonever changes):mainbefore this PRRSIZE_MAX0x1fffffffffffffffpasses,0x2000000000000000fails)SIZE_MAX >> 1size0 or aboveRSIZE_MAX"snprintf_s: bad argument"(orvsnprintf_s: …), a null pointer and 22SIZE_MAX >> 1acceptedbuffer[0]= 0, handler"…: bad format argument"buffer[0]= 0, no handler%n/%hn(also after truncation)buffer[0]= 0; handler"printf_s: %n disallowed"; the pointer is not written%sargument (also%.0s)"printf_s: bad %s argument"%ls/%Sargument"printf_s: bad %ls argument"sscanf_s / vsscanf_s (both behave the same):
mainbefore this PRunsigned int%s/%[field ofsizeor more characterssizecharacters stored without a terminator; matching failure, returns the items assigned so farbuffer[0]= 0%cwith a width abovesizesizecharacters and succeeds, consuming only thosebuffer[0]= 0%ls/%l[and%lcwith a width abovesize(titles' ownlibc.prx, measured by JJenkx)%lsand%l[follow the narrow rules;%lcstoressizeunits and succeeds, but consumes the whole width%lcconsumed only the stored charactersRSIZE_MAX"scanf_s: bad %c, %s, or %[ size"%s/%c/%[destination"scanf_s: bad %c, %s, or %[ argument", checked before reading input (also on empty input)EOF, no handler%por floating-point destinationEOFand"x"gives 0, without the handlerEOF%nincluded) has completedEOFEOF, handler"sscanf_s: bad argument"/"vsscanf_s: bad argument"EOF, no handler""with"x%d")EOFfscanf_s / vfscanf_s / scanf_s: a literal mismatch at the end of input now returns the assignments, as
sscanf_sdoes: empty input with"x%2c%n"returns 0 and leaveserrno, the%ntarget and the destination untouched, following JJenkx's CPU-only run of two referencelibcmodules (earlier heads andmainreturnEOF).%%at the end of input still returnsEOF. The stream forms were not run on a console.The -23 is the same with a recording handler, an empty one and
ignore_handler_s.set_constraint_handler_s,abort_handler_sandignore_handler_sare exported, and passing NULL reinstalls the default.The formatter's terminator: to leave the partial output unterminated on a violation,
FormatOutputnow writes the terminator once at the end instead of after every piece. Every caller goes throughFormatWindows, which does that at the end. On success every output is the same as before, which the existing formatting tests check.Not measured, recorded in
docs/dev/debt/libc.md:"<message>\n"before ending the process; AnyPS5's default still aborts without the message.%yis copied to the output by the console and still throws here.%hsargument was not measured.swscanf_s's size width (it still readsunsigned int) was not measured.Tests:
guest_formatting,guest_scan_count(also JJenkx's wide rows) andguest_stringscheck the measured cases, with the old expectations updated and size arguments passed assize_t.guest_scan_countfails if the -23 constant is changed.How the console was measured
libSceLibcInternal.sprxwas loaded withdlopen, and every function was taken from it withdlsym.~and integer destinations preset to -7.libcfmt3andlibcfmt4reinstall the default handler and end their own process with it, to see what it does.Console output (excerpt, copied unchanged)
Tested
d826fd16d3:mainwas merged in, with fix(libc): match bundled narrow scansets and scan directive parsing #12428; the unknown-conversion exit now comes before the secure block.guest_formatting,guest_wide_formatting,guest_scan_count,guest_stdio_variadic,guest_safe_errorsandguest_stringspass three runs in a row on Windows (MinGW, GCC 15.2) and on Linux (WSL, GCC);check_conventionspasses. Disregard the Linux result recorded for24f4242cbd: another checkout changed the shared tree while that build ran. This Linux run replaces it, on a tree nothing else touched.24f4242cbd:main(1d91f2966d, with fix(libc): read wide scanf fields byte by byte, as titles' libc.prx does #12468) was merged in and the secure bounds were re-applied on itssourcescanner: forsscanf_sandvsscanf_s,%ls,%lcand%l[keep the firstsizecharacters without a terminator when they do not fit, and%lcconsumes the rest of its width, which now counts bytes as fix(libc): read wide scanf fields byte by byte, as titles' libc.prx does #12468's loop does. Stream forms keepmain's behaviour.libc.mdkeeps fix(libc): read wide scanf fields byte by byte, as titles' libc.prx does #12468'sscanf_swording and this PR's. At this headguest_formatting,guest_scan_count,guest_wide_formatting,guest_stdio_variadic,guest_strings,guest_wide_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionsreports no errors.e16c92d39fmergesmain(93dbd0f82a, with feat(libc): add Dinkumware float bit helpers from firmware #8397); only thesscanf_sdebt line met feat(libc): add Dinkumware float bit helpers from firmware #8397's new_LDnormentry, and both are kept. At this head the twelve tests below pass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL, GCC 16.2), andcheck_conventionsreports no errors (onedebt-lengthwarning on alibc.mdentry this PR did not add).053ebd8a33:main(1ff6c8739b) was merged in. Onlylibc.mdmet, at thescanf_sandfreopen_sentries: it keeps this PR'sscanf_swording with JJenkx's end-of-input result andmain's newfreopen_sentry with its constraint handler calls. At this headguest_formatting,guest_scan_count,guest_wide_formatting,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).29d8de386f:main(3b32cc7b61, with fix(libc): read swscanf scanset ranges and string lengths as titles do #12420) was merged in. Onlylibc.mdmet, in the_WStoul/swscanf_sentry: it keeps fix(libc): read swscanf scanset ranges and string lengths as titles do #12420's scanset range, length and%pwording and this PR's measuredsscanf_scomparison (64-bit size, firstsizecharacters stored without a terminator). At this headguest_formatting,guest_scan_count,guest_wide_formatting,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).d00ac4ec91:main(0362b1521c, with feat(libc): implement dprintf and vdprintf #12933) was merged in. Onlylibc.mdmet: it keeps feat(libc): implement dprintf and vdprintf #12933's newdprintf/vdprintfentry and this PR's measuredsnprintf_s/vsnprintf_sentry, with the oldvsscanf_sentry still removed. At this headguest_formatting,guest_scan_count,guest_wide_formatting,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).4eaf64fee1:sscanf_s/vsscanf_stake a%cwidth by its low 32 bits and read one character when it is zero or aboveINT_MAX, following JJenkx's reference rows (%2147483648conabcstores one byte with size 2 or 4;%4294967298creads two).guest_scan_countgains those three rows, which fail on16a242bbaa. The stream scanner keepsmain's path until fix(libc): retain short stream character scan fields #13057 and fix(libc): retain ordinary short character scan fields #13119 land. At this headguest_formatting,guest_scan_count,guest_wide_formatting,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).16a242bbaa: the stream scanner (fscanf_s,vfscanf_s,scanf_s) returns the assignments for a literal mismatch at the end of input, following JJenkx's reference rows.guest_stdio_variadicgains the empty-input"x%2c%n"case (0,errno97,%n-77 and the 0xa5 destination untouched) and%%at the end of file (EOF); the first check fails on the previous head. The twelve tests listed below pass three runs in a row on Windows (WinLibs GCC) and on Linux (WSL Ubuntu, GCC);check_conventionspasses (the existing_WStouldebt-lengthwarning only).3b0fa2fc4d:main(157b02c4f1, with fix(libc): end sscanf and vsscanf at a q length on Linux and macOS #11852) was merged in. OnlyFormatting.cppmet, insscanf: it keeps fix(libc): end sscanf and vsscanf at a q length on Linux and macOS #11852's cut at aqlength directive (applied tosscanfandvsscanfonly, as onmain) and this PR'sScanGuestsignature with a null secure name. At this headguest_formatting,guest_scan_count,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).ec862a495a:%lcwith a width abovesizeconsumes the whole width, following JJenkx's run of titles'libc.prx(PPSA07923, PPSA05916).guest_scan_countgainsCheckWideFieldswith the eight rows of that table, and its two%lcrows fail onacb1ec494f. At this headguest_formatting,guest_scan_count,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).acb1ec494f:main(f80ce6cec1, with docs(libc): record feholdexcept, fegetexcept, setlocale and strcasecmp as measured on a PS5 #11121) was merged in. Onlylibc.mdmet: it keeps this PR'ssnprintf_s/vsnprintf_sandset_constraint_handler_swording and its removal of the oldvsscanf_sentry, and main'slocaleconventry with its removal of thesetlocaleentry. At this headguest_formatting,guest_scan_count,guest_stdio_variadic,guest_stringsandguest_safe_errorspass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).0055557985:main(5bdda3661e, with docs(libc): record that libSceLibcInternal does not export memmem or memccpy #10176 and fix(libc): leave errno alone for out-of-range float and double in swscanf #9973) was merged in. Onlylibc.mdmet: it keeps this PR's measuredsscanf_s/vsscanf_sand_WStoul/swscanf_sentries,main's firmware 13.60 export note onmemmem and memccpyand fix(libc): leave errno alone for out-of-range float and double in swscanf #9973's newfloating scan errnoentry. At this head the twelve tests below pass three runs in a row on Windows (WinLibs GCC 15.2) and on Linux (WSL2, GCC);check_conventionspasses (the onedebt-lengthwarning on the_WStoulentry, as before).2f05aac2d2:main(5b85225ef3, with feat(libc): add the Annex K stream printf, scanf and freopen_s functions #9527'sScanSource) was merged in5652af2d1a. This PR's measuredsscanf_s/vsscanf_srules were ported ontoScanSourceforStringSourceonly;StreamSourcekeepsmain'sfscanf_s/scanf_spath.2f05aac2d2makes feat(libc): add the Annex K stream printf, scanf and freopen_s functions #9527'sGuestStdioVariadicchecks expect the measuredsnprintf_s(-23 with a handler call) and undersizedsscanf_s%sresults instead of the old ones. At this head the twelve tests below pass three runs in a row on Windows and on Linux, and the 49 libc tests matchingscan|format|print|string|stdio|safe|constraint|bounds|crt|locale|widepass on Windows. Before that, head after mergingmainagain (9dbc017c71, with fix(libc): convert scanf integers as FreeBSD does on Windows #9479):efeb582327; onlycore/libs/tests/Formatting.cppmet, keeping this PR's constraint-handler helpers and measuredsscanf_stoo-small%scheck together with fix(libc): convert scanf integers as FreeBSD does on Windows #9479'sCheckIntegerScanWidthsand itsRunCheckscall. At this head the twelve tests below pass three runs in a row on Windows and on Linux (the Linuxpublic_headersaudit times out at 30 s on the WSL/mnt/ccheckout, unrelated to this change). Before that,main(ac65cf490e, with docs(debt): cite the bundled libc.prx for _Mtx_trylock, strdup and strndup #9613) was merged inb824e3b277; only thestrndupandsnprintf_sdebt lines met, keeping docs(debt): cite the bundled libc.prx for _Mtx_trylock, strdup and strndup #9613'sstrndupdisassembly reading and this PR's measuredsnprintf_sentry (the oldvsscanf_sline stays removed, as its measuredsscanf_sentry replaces it). At this head the twelve tests below pass three runs in a row on Windows and on Linux. Before that,main(66e6772ca2, with docs(libc): correct the RSIZE_MAX that swprintf_s and vswprintf_s assume #9360) was merged in6b9e2f1574; only thesnwprintf_sandswprintf_sdebt lines met, keeping this PR'ssnwprintf_swording andmain'sswprintf_slimit. Before that,main(f26434afa3, with refactor(libs): add full export headers for libs #10706) was merged in7b400cbcfe. The tests take their declarations fromlibc/include/Api.hpp.guest_formatting,guest_scan_count,guest_wide_formatting,guest_wide_stream_scan,guest_stdio_variadic,guest_locale,guest_strings,guest_wide_strings,guest_wide_conversion,guest_safe_errors,guest_crtandguest_bounds_checkingpass three runs in a row on Windows (WinLibs GCC) and on Linux (WSL Ubuntu, GCC), which now also builds the#ifndef _WIN32wide scan path.public_headersaudit andcheck_conventionspass (onedebt-lengthwarning on the_WStoulentry, already 3083 characters onmain).Windows 11, WinLibs GCC 15.2.0, Release: the 30 libc tests whose names cover formatting, scanning, strings, wide characters, streams, locales and bounds checking pass. Linux not built: the
#ifndef _WIN32wide scan path inScanGuestwas changed with the narrow rules and only passed ag++syntax check, so this PR relies on the Linux CI job to build and run it.Checklist
main; no other open PR implements the same functionsNotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file.mdfiles or images added to the repository (attach them to this PR)_WStoulentry, and feat(libc): implement std::_Atomic_assert #7851 (hypermoist) and feat(libc): implement lfind and lsearch #11621 (B-Howell) addlibc.mdentries next to the ones this PR edits (merge order only); fix(libc): print unknown printf conversions and ' as titles' libc.prx does #11907 (JJenkx) edits thesnprintf_stest block this PR rewrites intests/Formatting.cpp(merge order only); fix(libc): print %C, %S and a zero %lc in the printf families as titles' libc.prx does #12397 (JJenkx) adds a check in thesnprintf_stest block this PR rewrites intests/Formatting.cpp, and fix(libc): fail a 0x with no hex digit and keep errno for in-range floats in sscanf_s #12530, fix(libc): store a scanned NaN as the default quiet NaN in sscanf_s #12532 and fix(libc): check asctime_s and ctime_s arguments as titles' libc.prx does #12574 (JJenkx) editlibc.mdlines this PR changes (merge order only); fix(libc): check swprintf_s and snwprintf_s as titles' libc.prx does #12627 (JJenkx) rewrites thesnwprintf_sandswprintf_sentries this PR edits inlibc.md(merge order only); fix(libc): retain short wide scanf character fields #9863 (UnhealthyKraken) rewrites the wide scanner entry this PR edits inlibc.mdand lands first, as agreed on fix(libc): retain short wide scanf character fields #9863 (merge order only); fix(libc): check qsort_s arguments as titles' libc.prx does #12598 (JJenkx) rewrites theqsort_sentry next to thelibc.mdentries this PR edits (merge order only); JJenkx's ordinary short%cfield follow-up fix(libc): retain ordinary short character scan fields #13119 edits the scanner paths this PR changes and lands first, as agreed on this PR (merge order only); fix(libc): read wide scanf fields byte by byte, as titles' libc.prx does #12468 (JJenkx) rewrites the wide%c/%s/%[field loop this PR bounds inFormatting.cpp, and editstests/Formatting.cppandlibc.mdnext to this PR (merge order only); fix(libc): sort like the console's qsort and qsort_s #9688 has merged