Repository navigation
feat(libc): read 16-bit wide conversions in the scanf stream forms - #13696
SnekPolylepis wants to merge 1 commit into
Conversation
fscanf, vfscanf, scanf, vscanf and the _s forms threw on Linux for %ls, %lc, %l[, %S and %C. The stream scanner now reads a wide field one UTF-8 sequence at a time, as sscanf already does for a string, and stops at the first character the conversion does not accept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Progress report (85f2f7d → 81498b2)📈 System libraries: 26.34% (+0.01%, +3 implemented functions) ✅ 3 implemented
Changed libraries (implemented exports)
|
MarcZX10
left a comment
There was a problem hiding this comment.
Reviewed — changes requested
The new stream-scanning path rejects valid wide-scan formats whenever a literal dollar sign appears anywhere in the format.
What I ran
Reviewed head 81498b203b015d67f27a8cd4af1936518fd5c515 against PR base 85f2f7de53f35eb97589e1193791e2242e0a493e. The exact head has a clean merge preview against current main e49d43d6256b7c2283539d86b42325a36653275a. Environment: Linux x86_64, Python 3.11.2, GCC 12.2.0 detected; no compile was run. I ran:
python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 13696
git diff --check 85f2f7de53f35eb97589e1193791e2242e0a493e...81498b203b015d67f27a8cd4af1936518fd5c515
python3 tools/check_conventions.py --base 85f2f7de53f35eb97589e1193791e2242e0a493e --head 81498b203b015d67f27a8cd4af1936518fd5c515
python3 tools/pr_abi_audit.py --repo /marc/AnyPS5 --base 85f2f7de53f35eb97589e1193791e2242e0a493e --head 81498b203b015d67f27a8cd4af1936518fd5c515
python3 tools/pr_stack_check.py 13696 --repo boykopovar/AnyPS5 --output-dir /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13696-81498b203b01/stackResults
| Check | Result |
|---|---|
| Precheck wrapper | Its isolated snapshot lacked the workspace-local ABI and test-quality helper scripts; I reran both checks directly and manually verified test registration. |
| Diff check | Passed (exit 0; no output). |
| Conventions | 0 errors; one warning: the updated libc debt entry is 1,205 characters. |
| Export/NID audit | Passed; no findings. |
| Merge preview | Clean against main at e49d43d6256b7c2283539d86b42325a36653275a. |
| Test-quality heuristic | Its unregistered-test warning is a false positive: GuestStdioVariadic.cpp is registered in core/libs/prx/libc/CMakeLists.txt using ${LIBS_INCLUDE_DIR}/tests/GuestStdioVariadic.cpp. |
| Hosted CI | Conventions, intake, labels, eligibility, report, library-portability, and both Ubuntu Debug/Release register-context jobs passed. Ubuntu relinker, ASan, and Ubuntu Debug/Release register-context passed; Windows relinker and Windows product were still running, macOS relinker/register-context/write-watch jobs were queued, and Linux product was skipped. |
| Author-reported tests | Linux reports 38 related tests plus the new cases passing; Windows reports the libc and related test targets building and passing. I did not independently run these C++ tests. |
Unedited local check output
Conventions:
docs/dev/debt/libc.md:211: warning: [debt-length] Technical debt entry over 1000 characters: state the gap first (what differs from the console, what is unverified, what throws) and keep only the behaviour it needs: 1205 characters
1 findings, 0 errors; GitHub shows at most 10 error annotations, the job summary lists all
Precheck helper limitation (the direct ABI audit was rerun successfully afterward):
/usr/bin/python3: can't open file '/tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-13696-81498b203b01/head-81498b203b01-d671220b/tools/pr_abi_audit.py': [Errno 2] No such file or directory
Direct ABI audit output excerpt:
ABI audit: passed
Test-quality heuristic:
core/libs/tests/GuestStdioVariadic.cpp:1: possible-unregistered-cpp-test: Changed C++ test source path was not found literally in CMake files; inspect registration, generated source lists, and workflow coverage.
Heuristic findings require manual interpretation.
Stack check:
# PR stack check — fresh
Target: https://github.com/boykopovar/AnyPS5/pull/13696
Target branch tip: `e49d43d6256b7c2283539d86b42325a36653275a`
All heads unchanged: **True**
Dependency order: #13696
## Individual merge previews
- PR #13696: **clean** against current base; head `81498b203b015d67f27a8cd4af1936518fd5c515`; changed paths: none reported
Negative control
| Assertion | Change made to code under test | Did the new test fail? |
|---|---|---|
A literal $ adjacent to a wide conversion is accepted as format text or a scanset character. |
None; no exact-head C++ test binary was available without building. | Not exercised locally. |
Findings
Blocking
ScanGuestStream calls RequireNoPositionalWideScan whenever it sees a wide conversion, but that helper rejects any $ byte in the entire format rather than only $ used in a conversion specifier. Thus valid formats such as "$%ls" and %l[$] throw NotImplemented before scanning. Please make the positional check parse conversion directives (including scansets) and add a stream regression case for a literal dollar with a wide conversion.
Non-blocking
The convention checker warns that the revised debt entry is 1,205 characters; it reports no errors.
Sources
- New stream-scanner call
- Positional-wide helper call
- Helper's whole-format dollar check
- FreeBSD 11.4 scanner treats non-
%format characters as literals
Not verified
I did not build or run the C++ test executable, run the scanner on a console, or verify target-specific locale behavior. Hosted jobs still running/queued at the check refresh are not reported as passing.
To get this to a good state
Narrow positional-syntax detection and add the literal-dollar regression case. After a new head is pushed, I will rerun the same no-build checks and review the changed scanner path.
|
@SnekPolylepis thanks, the lead-byte look-ahead (no push-back) is a neat way to stop a stream after the last character used, and the cases you added exercise it well. Three points before this can go forward.
|
|
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.
|
What
On Linux,
fscanf,vfscanf,scanf,vscanfand the_sforms threwNotImplementedfor the 16-bit wide conversions (%ls,%lc,%l[,%S,%C).sscanfalready read them. This PR adds a stream version of that wide branch to the shared scanner:ReadWideScanCharacter. It stops at the first character the conversion doesn't accept, so the stream stops after the last character used.fscanfon Linux now goes throughvfscanf.vfscanfsends formats with a wide conversion to the guest scanner, andScanGuestStreamtakes asecureflag so the plain and_sforms share it._ssizing, undersized-buffer handling and positional-argument rejection behave as they do forsscanf_s.I updated the two scanf entries in
docs/dev/debt/libc.mdto match. Nothing was measured on a console: this follows the existingsscanfbehavior and FreeBSD's scanf.Tested
guest_stdio_variadicpass:%ls,%S,%l[with a width,%lc, UTF-8 input (été), where the stream stops, an undersizedfscanf_sbuffer, and EOF. So do the 38 related scan, format and stdio tests.libc,guest_stdio_variadic,guest_wide_stream_scanandguest_wide_formattingbuild and pass. The new cases are Linux-only, because the Windows scanner already handles wide conversions.check_conventions.pypasses.pr_overlap.pyfinds no conflicts, only the shareddocs/dev/debt/libc.md.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)🤖 Generated with Claude Code