Skip to content

fix(libc): keep rejected wide scan bytes and set EBADF for a negative fdopen - #15329

Open
MarcZX10 wants to merge 4 commits into
boykopovar:mainfrom
MarcZX10:r2/r53-libc-big
Open

MarcZX10 wants to merge 4 commits into
boykopovar:mainfrom
MarcZX10:r2/r53-libc-big

Conversation

@MarcZX10

@MarcZX10 MarcZX10 commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

What

Two libc fixes:

  • Wide scanf pushback: a rejected byte was cast to a signed char, so 0xff became EOF and was dropped from the stream. The byte is now kept.
  • fdopen with a negative descriptor returned NULL without setting errno. It now sets EBADF.

Commits:

  • 7f6a41e fix(libc): keep a rejected wide scan byte in the stream
  • 18cfbc8 test(libc): keep a rejected 0xff byte in a wide scan stream
  • 79b42ea fix(libc): set EBADF when fdopen gets a negative descriptor
  • 4fb7382 test(libc): check fdopen errno for a negative descriptor

Tested

Not verified

  • The multibyte double-feed in the wide scan decoder (Formatting.cpp) looks like a real defect, but existing tests pin the current rejection. It is left for a maintainer decision.
  • Not built on Windows or macOS.
  • Overlap: fix(libc): retain short wide scanf character fields #9863 changes short wide scanf character fields in the same area. The changes are in different lines, but the PRs may conflict textually.

Checklist

  • Based on current main at the time of testing; fix(libc): retain short wide scanf character fields #9863 covers different fields, not the pushback
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

The wide scanner pushed back a rejected byte as a signed char. A 0xff byte
became -1, which is EOF, and PutBack ignores EOF, so the byte was consumed
and never returned to the stream. This affects a lone 0xff as well as one
that follows a lead byte.

Pass the byte as unsigned so every value survives the pushback.
A stream whose first byte is 0xff must still hold that byte after %ls
rejects it.
fdopen returned NULL for a negative descriptor without setting errno, so
the caller saw whatever error was left over. The Windows path already
reports EBADF for an invalid descriptor, and fdopendir reports 9 for the
same input.

Set errno to EBADF on that path.
fdopen with descriptor -1 must return NULL and set EBADF.
@github-actions github-actions Bot added the libc label Nov 3, 2026

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no blocking findings

The reviewed source changes appear correct; hosted build jobs are still pending, so this is a comment rather than approval.

What I ran

Reviewed PR #15329 at head 4fb73821a711840e27fdb808e7a89f275406949c, based on 5cb015caaaaf83f8ee431414ee6a457b5b307d49. The stack checker previewed the head against current main tip 7feb37ee3e30e10139b483fb4df689d5b5b69ab8 and found a clean merge. Environment: Debian Linux x86_64, Python 3.11.2, GCC 12.2.0. I did not build or run CTest.

git diff --check 5cb015caaaaf83f8ee431414ee6a457b5b307d49...4fb73821a711840e27fdb808e7a89f275406949c
python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 15329
python3 tools/pr_test_quality.py --root /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/head-4fb73821a711-b16333c3 --json core/libs/tests/FilePosition.cpp
python3 tools/pr_overlap.py --branch refs/review/pr-15329-20261103 --repo boykopovar/AnyPS5
gh pr checks 15329 --repo boykopovar/AnyPS5
git grep -n 'file_position_tests\|FilePosition.cpp' refs/review/pr-15329-20261103 -- core/libs
for p in core/libs/prx/libc/src/FileAndHeap.cpp core/libs/prx/libc/src/Formatting.cpp core/libs/tests/FilePosition.cpp; do gh pr list --repo boykopovar/AnyPS5 --state open --search "path:$p" --limit 100 --json number,title,headRefOid --jq '.[] | [.number,.headRefOid,.title] | @tsv'; done

Results

Check Result Note
Diff and conventions passed Patch and required PR fields pass.
Test registration passed CMake registers FilePosition.cpp; heuristic warning was a false positive.
Current-main merge preview passed Exact head merges cleanly; base has advanced.
Overlap helper failed The helper could not parse its GitHub response; path searches found no open PRs changing these files.
Hosted policy checks passed Conventions, intake, eligibility, labels, report, and portability passed.
Hosted build tests not run Build matrix remains pending; full Linux job was skipped.
Precheck table and raw output

Precheck table, copied from its report:

Check Status Command / reason
build_and_compile not_applicable The precheck deliberately does not configure, build, or compile AnyPS5.
diff_check passed git diff --check 5cb015caaaaf83f8ee431414ee6a457b5b307d49...4fb73821a711840e27fdb808e7a89f275406949c
conventions_and_pr_template passed /usr/bin/python3 tools/check_conventions.py --base 5cb015caaaaf83f8ee431414ee6a457b5b307d49 --head 4fb73821a711840e27fdb808e7a89f275406949c --title fix(libc): keep rejected wide scan bytes and set EBADF for a negative fdopen --body /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/pr-body.md
changed_export_abi_audit failed /usr/bin/python3 tools/pr_abi_audit.py --base 5cb015caaaaf83f8ee431414ee6a457b5b307d49 --head 4fb73821a711840e27fdb808e7a89f275406949c --json
python_syntax not_applicable No changed Python implementation files.
related_python_unit_tests not_applicable No changed tools/ module has an existing sibling tools/tests/test_<module>.py suite.
python_test_registration not_applicable No changed test_*.py files.
live_dependency_and_mergeability_check passed /usr/bin/python3 /marc/AnyPS5/tools/pr_stack_check.py 15329 --repo boykopovar/AnyPS5 --output-dir /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/stack
build_dependent_cpp_tests not_applicable Not run: C++ tests need exact-head binaries, which require a build; the precheck does not build.
test_quality_heuristics failed /usr/bin/python3 /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/head-4fb73821a711-b16333c3/tools/pr_test_quality.py --root /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/head-4fb73821a711-b16333c3 --json core/libs/prx/libc/src/FileAndHeap.cpp core/libs/prx/libc/src/Formatting.cpp core/libs/tests/FilePosition.cpp
negative_controls not_applicable No changed Python test module in tools/ can be run as a no-build base-source control.
All conventions checks passed.
{"findings":[{"path":"core/libs/tests/FilePosition.cpp","line":1,"kind":"possible-unregistered-cpp-test","message":"Changed C++ test source path was not found literally in CMake files; inspect registration, generated source lists, and workflow coverage."}]}
pr_overlap: Invalid \\uXXXX escape: line 1 column 1807715 (char 1807714)

The CMake search found add_test_executable(file_position_tests ${LIBS_INCLUDE_DIR}/tests/FilePosition.cpp) and add_test(NAME file_position COMMAND file_position_tests), so the heuristic registration warning is a false positive. The precheck's ABI and test-quality subprocesses could not run because those helper files are absent from the isolated PR snapshot; the local test-quality helper produced the warning above.

Raw hosted CI output
edge-watch (macos-15)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429040
edge-watch (macos-15-intel)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429236
register-context (macos-15-intel, Debug)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429195
register-context (macos-15-intel, Release)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429087
register-context (ubuntu-latest, Debug)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429126
register-context (ubuntu-latest, Release)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429155
relinker (macos-latest, clang++)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429134
relinker (macos-latest, clang++, x86_64)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429061
relinker (ubuntu-latest, g++)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429113
relinker (windows-latest, g++)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429193
relinker-asan	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429063
conventions	pass	19s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523461/job/125636677244
intake	pass	5s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523475/job/125636676965
library-portability	pass	1m18s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523744/job/125636675882
write-watch (macos-15-intel)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429104
labels	pass	8s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523463/job/125636677342
write-watch (macos-15)	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429071
linux	skipping	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654431163
windows	pending	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654428980
eligibility	pass	6s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125636676475
report	pass	48s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523705/job/125636675586

Negative control

No code mutation or negative-control test was run. The changed C++ tests require an exact-head build; the existing test asserts that a negative descriptor returns null with errno == EBADF and that an invalid wide-scan byte remains readable.

Findings

Blocking

None found in the three changed files.

Non-blocking

  • The new wide-scan test covers an invalid 0xFF as the first byte, which exercises the first PutBack call. A two-byte input such as 0xC2 0xFF would also exercise restoration of a previously held lead byte and make the second pushback path explicit. This is a test-coverage suggestion; the current code's unsigned-byte conversions are consistent with StreamSource::PutBack and ungetc's EOF sentinel.

Sources

Not verified

No local build, CTest, Windows or macOS runtime test, or PS5 console behavior was run. Hosted Windows, relinker, register-context, edge-watch, and write-watch jobs were pending at the last check; Linux was skipped. No independent review was performed; this PR is authored by MarcZX10. The full overlap helper failed, and path searches are not a complete overlap audit.

To get this to a good state

No code change is required by this review. Let the hosted jobs finish and obtain an independent review before relying on approval. If the optional two-byte regression is added, rerun the precheck and file_position CTest on the new head; I will recheck that head and its hosted results.

@MarcZX10

MarcZX10 commented Nov 3, 2026

Copy link
Copy Markdown
Contributor Author

Reviewed — no blocking findings

The two changes fix the reported byte-pushback and fdopen error cases; I found no blocker in the exact diff.

What I ran

Reviewed all three changed files at head 4fb73821a711840e27fdb808e7a89f275406949c, against PR base 5cb015caaaaf83f8ee431414ee6a457b5b307d49. The merge preview was clean against current main f6232fcfda70644495273f6b8dd88cf0603463d6. Environment: Debian 12 x86_64, Linux 6.1.0-54-amd64, Python 3.11.2, GCC 12.2.0. The PR description reports Linux CTest and negative-control runs; I did not independently run those.

python3 tools/pr_precheck.py --repo boykopovar/AnyPS5 --pr 15329
git diff --check 5cb015caaaaf83f8ee431414ee6a457b5b307d49...4fb73821a711840e27fdb808e7a89f275406949c
gh pr checks 15329 --repo boykopovar/AnyPS5

Results

Check Result Note
Diff and conventions passed Exact-head checks passed.
Current-main merge preview passed Clean against current main.
Hosted checks passed Windows and applicable macOS, relinker, and policy jobs passed.
Linux workflow job not applicable Skipped by the workflow.
Local build and CTest not run Author reports Linux runs; not independently repeated.
Optional precheck helpers failed ABI and test-quality scripts are absent from the isolated snapshot.
Precheck table and hosted output
# PR precheck report — checks failed

PR: https://github.com/boykopovar/AnyPS5/pull/15329
Head: `4fb73821a711840e27fdb808e7a89f275406949c`
Base: `5cb015caaaaf83f8ee431414ee6a457b5b307d49`
Head unchanged at completion: **True**
Base unchanged at completion: **True**

| Check | Status | Command / reason |
|---|---|---|
| build_and_compile | not_applicable | `The precheck deliberately does not configure, build, or compile AnyPS5.` |
| diff_check | passed | `git diff --check 5cb015caaaaf83f8ee431414ee6a457b5b307d49...4fb73821a711840e27fdb808e7a89f275406949c` |
| conventions_and_pr_template | passed | `/usr/bin/python3 tools/check_conventions.py --base 5cb015caaaaf83f8ee431414ee6a457b5b307d49 --head 4fb73821a711840e27fdb808e7a89f275406949c --title fix(libc): keep rejected wide scan bytes and set EBADF for a negative fdopen --body /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/pr-body.md` |
| changed_export_abi_audit | failed | `/usr/bin/python3 tools/pr_abi_audit.py --base 5cb015caaaaf83f8ee431414ee6a457b5b307d49 --head 4fb73821a711840e27fdb808e7a89f275406949c --json` |
| python_syntax | not_applicable | `No changed Python implementation files.` |
| related_python_unit_tests | not_applicable | `No changed tools/ module has an existing sibling tools/tests/test_<module>.py suite.` |
| python_test_registration | not_applicable | `No changed test_*.py files.` |
| live_dependency_and_mergeability_check | passed | `/usr/bin/python3 /marc/AnyPS5/tools/pr_stack_check.py 15329 --repo boykopovar/AnyPS5 --output-dir /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/stack` |
| build_dependent_cpp_tests | not_applicable | `Not run: C++ tests need exact-head binaries, which require a build; the precheck does not build.` |
| test_quality_heuristics | failed | `/usr/bin/python3 /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/head-4fb73821a711-8ff57a90/tools/pr_test_quality.py --root /tmp/anyps5-pr-precheck/boykopovar-AnyPS5-pr-15329-4fb73821a711/head-4fb73821a711-8ff57a90 --json core/libs/prx/libc/src/FileAndHeap.cpp core/libs/prx/libc/src/Formatting.cpp core/libs/tests/FilePosition.cpp` |
| negative_controls | not_applicable | `No changed Python test module in tools/ can be run as a no-build base-source control.` |

The ABI and test-quality failures were launch errors because those helper scripts are not present in the isolated PR snapshot. The test file already belongs to the existing file_position CTest target.

Exact-head hosted checks:

conventions	pass	19s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523461/job/125636677244
edge-watch (macos-15)	pass	55s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429040
edge-watch (macos-15-intel)	pass	1m49s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429236
eligibility	pass	6s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125636676475
intake	pass	5s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523475/job/125636676965
labels	pass	8s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523463/job/125636677342
library-portability	pass	1m18s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523744/job/125636675882
register-context (macos-15-intel, Debug)	pass	1m31s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429195
register-context (macos-15-intel, Release)	pass	1m21s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429087
register-context (ubuntu-latest, Debug)	pass	31s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429126
register-context (ubuntu-latest, Release)	pass	38s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429155
relinker (macos-latest, clang++)	pass	4m57s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429134
relinker (macos-latest, clang++, x86_64)	pass	9m5s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429061
relinker (ubuntu-latest, g++)	pass	4m32s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429113
relinker (windows-latest, g++)	pass	9m57s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429193
relinker-asan	pass	1m59s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429063
windows	pass	5m8s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654428980
write-watch (macos-15)	pass	57s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429071
linux	skipping	0	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654431163
report	pass	48s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523705/job/125636675586
write-watch (macos-15-intel)	pass	1m16s	https://github.com/boykopovar/AnyPS5/actions/runs/41550523808/job/125654429104

Negative control

I did not run a negative control. The PR description reports that removing each fix makes its corresponding test fail, but those runs are author-reported. The new tests assert that 0xff remains available after the rejected wide scan and that fdopen(-1, "r") returns null with errno == EBADF.

Findings

Blocking

None found in the changed behavior.

Non-blocking

While tracing the modified wide-scan path, I confirmed the PR description's separate multibyte concern: after mbrtowc_nid_postfix returns incomplete, state retains the lead byte, but the next iteration passes the pending buffer from its beginning again. For a valid two-byte sequence, the lead is therefore fed twice and the continuation byte is rejected. This predates this PR's diff and is separate from preserving a rejected byte; consider tracking it in a focused follow-up with valid multibyte %ls coverage.

Sources

Not verified

I did not run a local build, CTest, the author's negative controls, or console behavior. The hosted Linux workflow job was skipped; the Linux CTest result in the PR description was not independently reproduced.

To get this to a good state

No change is required for this diff based on the checks above. Consider a separate follow-up for valid multibyte wide scanning. I would rerun the same precheck and relevant tests on a new head; this is a MarcZX10-authored PR, so my result is not independent approval.

@bunbeans2-arch

Copy link
Copy Markdown
Contributor

A Windows run with GCC 16: Windows 10.0.22631 (Windows 11), i9-9900K, MSYS2 UCRT64 GCC 16.1.0 (Rev5), Release, this PR (4fb73821a7) merged into main d1ae628bc2.

file_position with this PR's two new checks:

  • ❌ Before: same tree with only FileAndHeap.cpp and Formatting.cpp put back to main (both rebuilt). It failed 5 of 5 runs with File position check failed at line 45 (abort, exit 0xc0000409). Line 45 is Require(std::fgetc(input.GetHandle()) == 0xff);: after the %ls scan rejects the 0xff byte, the old code doesn't leave it in the stream.
  • ✅ After: with this PR it passed 5 of 5.
  • main alone (its own file_position) passed 3 of 3.

The test stops at line 45, so the old side didn't reach the fdopen(-1) / EBADF check on line 50 👍

AI-assisted: yes (Claude Code)

@XairRrR XairRrR left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — changes requested

Both fixes change behaviour that main records as the console's, and each one makes an existing test fail: fdopen breaks guest_standard_streams and the 0xff pushback breaks guest_wide_stream_scan.

What I ran

Head 4fb73821a711840e27fdb808e7a89f275406949c merged into main 4f41f4c375f5abb487dbd184fbc150f31994d762 (merged tree 7acfdc3af15da4d0b228fa815430f9b1c301091e). Debian 13 VM, GCC 14.2.0, Release, Ninja.

git diff --check 4f41f4c375f5abb487dbd184fbc150f31994d762...4fb73821a711840e27fdb808e7a89f275406949c
python3 tools/check_conventions.py --base 4f41f4c375f5abb487dbd184fbc150f31994d762
ctest --test-dir build --output-on-failure -R '^(guest_standard_streams|guest_wide_stream_scan|file_position|guest_formatting)$'
# attribution: Formatting.cpp from main only, then FileAndHeap.cpp from main too
git show 4f41f4c375f5:core/libs/prx/libc/src/Formatting.cpp > core/libs/prx/libc/src/Formatting.cpp
ninja -C build guest_standard_stream_tests guest_wide_stream_scan_tests file_position_tests
ctest --test-dir build --output-on-failure -R '^(guest_standard_streams|guest_wide_stream_scan|file_position)$'
git show 4f41f4c375f5:core/libs/prx/libc/src/FileAndHeap.cpp > core/libs/prx/libc/src/FileAndHeap.cpp
ninja -C build guest_standard_stream_tests guest_wide_stream_scan_tests file_position_tests
ctest --test-dir build --output-on-failure -R '^(guest_standard_streams|guest_wide_stream_scan|file_position)$'
# restore the merged files, rebuild, git status --porcelain (clean)

Results

Check Result
git diff --check clean
check_conventions.py passed
Build (selected tests) passed
file_position passed
guest_formatting passed
guest_wide_stream_scan failed: new failure compared with the baseline of the same main SHA
guest_standard_streams failed: new failure compared with the baseline of the same main SHA
Other tests in the selected run 9 known failures that also fail on main. guest_net_ctl was skipped on main too. None of these is caused by this PR
Merged tree
2/4 Test #829: guest_wide_stream_scan ...........Subprocess aborted***Exception:   0.01 sec
failed: wide field failure keeps the measured stream position
3/4 Test #889: guest_standard_streams ...........Subprocess aborted***Exception:   0.01 sec
Attribution
  • With only Formatting.cpp restored from main, guest_wide_stream_scan passes and guest_standard_streams still fails.
  • With FileAndHeap.cpp also restored, guest_standard_streams passes.

So each failure comes from one of the two fixes in this PR. The baseline SHA is the same as main, so neither failure comes from main.

Negative control

I restored both production files from main and rebuilt. file_position then fails, so the new checks do catch the old behaviour. This agrees with the author's report and with the earlier Windows run in the discussion. I then restored the merged files, rebuilt, and confirmed that git status --porcelain is empty.

Findings

Blocking

  1. fdopen with a negative descriptor contradicts the measured console behaviour and fails guest_standard_streams.

    • The change is at core/libs/prx/libc/src/FileAndHeap.cpp:443.
    • Commit 3dac7eb76c ("…skip the access check as measured on a PS5") deliberately leaves errno unchanged on this path.
    • GuestStandardStreams.cpp:827-829 pins that errno stays 1234 for -1, -2 and INT_MIN.
    • The libc debt entry says the same: "a negative descriptor then returns null without setting errno" (docs/dev/debt/libc.md:24).
    • The PR's reasoning compares with the Windows path and with fdopendir. Neither of those is evidence of what the console's fdopen does.
    • Fix: drop this change. Or, if a PS5 measurement shows EBADF, cite it, update the existing test and the debt entry, and remove the new CheckFdopenNegativeDescriptor.
  2. The 0xff pushback change breaks the pinned wide-scan results in guest_wide_stream_scan.

    • The change is at core/libs/prx/libc/src/Formatting.cpp:351-352.
    • The signed char cast was added in 8a0ba60209 together with cases that expect the rejected 0xff to be consumed. For example, "\xff\x7a" with %ls expects position 1 and next byte 0x7a. See GuestWideStreamScan.cpp:270-272.
    • The assertions there are labelled "measured" (L290-L294). This matches a console ungetc((char)0xff) colliding with EOF.
    • With this PR, the test aborts at "wide field failure keeps the measured stream position".
    • Note that the scanf debt entry (libc.md:246) says the stream position after a failed wide field "was not measured". That contradicts the test labels, so the source of truth is unclear on main itself.
    • Fix: either keep the current behaviour, or provide a console measurement showing the byte stays in the stream. In the second case, update the GuestWideStreamScan.cpp rows (all \xff cases, %S included) and the debt entry in the same PR.
  3. The description's test claims leave out the failing tests.

    • The description reports only file_position and guest_formatting.
    • The two tests that cover these exact paths (guest_standard_streams, guest_wide_stream_scan) fail.
    • The two earlier review comments and the Windows run also checked only file_position, so none of them caught this.

Non-blocking

None.

Not verified

  • Console behaviour of either path: no PS5 is available here.
  • Windows and macOS builds.
  • The full test suite was not run. The selected tests the change reaches were run by the script, and the four above were rerun by hand.

To get this to a good state

  • Drop the fdopen change unless a PS5 measurement supports EBADF. If one does, change the existing GuestStandardStreams.cpp expectation and the debt entry in the same PR, with the measurement cited.
  • Do the same for the wide-scan pushback: keep the existing behaviour, or measure on a console and update GuestWideStreamScan.cpp and docs/dev/debt/libc.md together.
  • Rerun guest_standard_streams, guest_wide_stream_scan, file_position and guest_formatting, and report all four in the description.

@TechLevelZero

Copy link
Copy Markdown
Contributor

❌ AMD GPU test: failed

PR head 4fb7382 merged onto main 4f41f4c · tested 2026-11-03 12:59 UTC · 29 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ❌ 3,685 passed · 16 failed (2 new: 2 pass on main with the PR's tests, 12 also fail on main, 2 unstable on main) · 60 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 3,761 of 3,811 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (1332 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.0 s, ⚠️ agc_driver_graphics_maps_fallback 96.3 s, ⚠️ agc_driver_graphics 83.8 s, ⚠️ public_headers 54.6 s, ⚠️ agc_driver_bda_device 42.7 s

Failing tests

This PR changes test files, so each failing test was also built and run on main with only the PR's test changes applied. ✅ there means the failure comes from the PR's other changes; ❌ means the test fails on main too, so this run does not show the PR caused it.

Test With this PR Same test on main 4f41f4c (main + this PR's test changes only)
guest_standard_streams ❌ failed ✅ passed
guest_wide_stream_scan ❌ failed ✅ passed
guest_standard_streams: Subprocess aborted (also failed when re-run alone), assertion and diagnostics
ctest: Subprocess aborted


guest_wide_stream_scan: Subprocess aborted (also failed when re-run alone), assertion and diagnostics
ctest: Subprocess aborted

failed: wide field failure keeps the measured stream position
Unstable on main (2, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 7 of the last 9 main runs
agc_driver_store_over_untracked: failed in 1 of the last 9 main runs
Failing on main too (12, not counted against this PR)
agc_driver_alpha_to_coverage_sample_mask_export
agc_driver_guest_memory_lifetime_direct
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_depth_buffer_clear
agc_driver_native_depth_clears
agc_driver_native_multisample_depth
agc_driver_submit_progress
agc_submit_progress
agc_submit_progress_no_timeline
guest_mmap_executable
guest_socket_options_multicast
Validated but not compared (3, not in the main baseline's validation pass)
guest_job_manager_worker_spin
guest_standard_streams
guest_wide_stream_scan
Validation IDs already present on main (4 IDs in 764 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (764 tests): agc_compute_pipeline_replay, agc_driver, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_address_passes_targets_split, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_alpha_to_coverage_sample_mask_export, and 756 more
VUID-vkCmdCopyImage-srcImage-01548 (12 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 4 more
VUID-vkCmdCopyImage-srcImage-01551 (12 tests): agc_driver_depth_clear_hle, agc_driver_depth_plane_buffer_memory, agc_driver_depth_plane_cpu_write_after_memo, agc_driver_depth_plane_cpu_write_after_page_unwatch, agc_driver_depth_plane_cpu_write_after_partial_unwatch, agc_driver_depth_plane_partial_store, agc_driver_depth_plane_partial_store_unimported, agc_driver_depth_storage_dispatch, and 4 more
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (2 tests): agc_driver_prepared_exports, agc_driver_srgb8_color_target
Skipped (60)
agc_driver_bda_reads_shadowed_results: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_bda_reads_shadowed_results_per_build: skipped, the device reports watched host memory written when it imports or reads it
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_copied_writer_label_order_drain: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_image_table_vouched_lookups: skipped, the device reports 4 of 4 host-imported pages written after a GPU read, so a watched imported table cannot be vouched for
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_unit_shadow: skipped, the device does not import watched host memory for unit shadows
agc_driver_unit_shadow_budget: skipped, the device does not import watched host memory for unit shadows
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
agc_host_import_sparse: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_idle_publish_wait: skipped, the device reports 4 of 4 host-imported pages written after a GPU read, so a forced watch of the import reads its submissions as CPU stores
agc_import_settle_initial_dcc: skipped, the device has no deferred settle of host imports: imports under 1 MiB wait for one only on Windows
agc_shadowed_key_stores: skipped, the device imports no watched host memory under a unit shadow
agc_small_tiled_shadow_label: skipped, host imports are unavailable: the test block is not imported and watched
agc_storage_clear_hand_over: skipped, the device imports no watched host memory for the clear-key hand-over
agc_unit_shadow: skipped, the device does not import watched host memory for unit shadows
agc_unit_shadow_completion_store: skipped, the device reports watched host memory written when it imports or reads it
guest_http_uri_locale: 
guest_net_ctl: skipped, the host has no IPv4 address
guest_video_out_color_space: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_hdr: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_high_frame_rate: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_output_mode: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_resolution_status: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
guest_video_out_wqhd_detection: skipped, no display or Vulkan device: SDL_InitSubSystem(VIDEO | GAMECONTROLLER) failed: wayland,x11 not available
video_out_flip_aftergpu: skipped, no display or Vulkan device: DisplayWindow: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
video_out_flip_backtoback: skipped, no display or Vulkan device: DisplayWindow: Vulkan support i
Reproduce
git fetch origin 4fb73821a711840e27fdb808e7a89f275406949c 4f41f4c375f5abb487dbd184fbc150f31994d762
git checkout 4f41f4c375f5abb487dbd184fbc150f31994d762 && git merge --no-ff 4fb73821a711840e27fdb808e7a89f275406949c
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1
# the failing tests, on this merge and on main:
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(guest_standard_streams|guest_wide_stream_scan)$' --parallel 1 -V

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Hi MarcZX10,

A heads-up from our Windows test run, in case it helps. With this PR at 4fb73821a7 merged onto main 4f41f4c375 (and nothing else), two tests crash on Windows 11 with exit code 0xc0000409 (STATUS_STACK_BUFFER_OVERRUN): guest_standard_streams and guest_wide_stream_scan. On plain main at the same commit, on the same machine, both pass. We first saw it in a batch with other PRs; the PR-alone run above isolates it to this change.

We didn't get a Linux result for it in that run. Since the change is in the wide scan path (Formatting.cpp) and fdopen (FileAndHeap.cpp), one of those two hunks is likely where the Windows stack check trips.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants