Skip to content

fix(libc): format guest wide printf arguments on Linux - #1804

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
gdrosa:fix/libc-guest-wide-printf
Oct 10, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
gdrosa:fix/libc-guest-wide-printf

Conversation

@gdrosa

@gdrosa gdrosa commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

What

On Linux the narrow printf family passes %ls/%S guest strings to the host formatter, which reads 32-bit wchar_t elements instead of the guest's 16-bit units. Route formats containing %ls, %S, %lc or %C through the existing guest formatter. Formats without guest wide conversions retain their native Linux path, including positional arguments and escaped percent signs. Guest va_list inputs remain unchanged.

The common formatter also dropped a NUL %lc/%C argument because it passed that character through %s. Format that one case through %c, preserving the byte and output count. This follows FreeBSD 11 vfprintf, whose wide-character branch emits the complete wcrtomb result, including a converted NUL.

Extend the existing guest_formatting regression on both platforms and update TechnicalDebt. The UTF-16-to-UTF-8 conversion policy is the existing Windows policy: it does not establish console locale behavior or validate invalid UTF-16. Positional or other unsupported conversions in a format that needs the guest formatter still throw; ordinary Linux formats keep host support.

Independent of #1507 (wcsrtombs), #1511 (swprintf), #1573 (Windows numeric flags), #1614 (locale character conversions) and #1708 (large collate storage). Merge simulations with the current heads of #1511 and #1573 are clean. #1708 conflicts only in adjacent TechnicalDebt entries; the implementation files merge cleanly. Rebase the second PR after the first merges, preserving both debt updates. No functional dependencies.

Tested

Windows x64 Release, portable GCC 15.2.0 and CMake/Ninja in the existing virtualenv, SPIRV-Tools disabled: all 34 libc CTests pass. The real-DLL PoC covers all 14 formatting exports, C and UTF-8 host locales, mixed argument types, output capacities, precision, Unicode surrogate pairs, NUL characters, protected page boundaries, allocation and file/stdout output, preserved va_list state and concurrent calls.

Linux validation on Ubuntu 24.04, GCC 13.3, Release, SPIRV-Tools enabled, exact commit 21d21da3857e: the same regression on unpatched main fails only guest_formatting (36/37 tests pass). The fix passes 37/37 libc tests, repeated three times. The full suite, requested with repeat until-fail:3, has 291 passes, 194 GPU-dependent skips and 1 failure(s) out of 486 tests. The complete project, patched libraries and test-registration check pass. The Linux real-library PoC passes 5,974 checks; Windows passes 5,976. Full Windows project suite not rerun for this contribution. Build tools are installed in virtualenvs or taken from the existing portable toolchain; no system installations.

The full suite has one failure: agc_driver_flip reports "failed flip was completed successfully". This is consistent with a pre-existing notification race: QueueWorker.cpp calls ReportFailure before failing the active submission's flip requests; Lifecycle.cpp publishes the exception and wakes idle waiters. Flip.cpp then reads the callback counter after those waiters return, which can happen before the callback. These three files are byte-identical to the unpatched base. This diagnosis is source analysis; the unpatched base was not rerun locally to reproduce the failure. Upstream Build on that base passed, so this result should not be presented as a deterministic base failure. The printf change does not modify the AGC path.

Reviewed all 386 open PR file lists and the complete relevant diffs. No other PR implements Linux routing for guest wide printf arguments or the NUL-character correction. No game or original console libc execution.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw; silent stubs are listed in TechnicalDebt
  • No investigation notes or reports added to the repository
  • No new third-party dependencies
  • Generic behaviour
  • Depends on: none
  • AI-assisted: yes

@WifeInLantern

Copy link
Copy Markdown

Tested on Windows 11 (26200), WinLibs GCC 15.2.0 r7, Release, BUILD_TESTING=ON, #1804 (21d21da3) merged onto current main — clean merge, no conflicts.

  • guest_formatting, guest_wide_formatting, guest_wide_strings, guest_strings, guest_wcsrtombs_s, guest_locale pass; check_conventions.py --base origin/main passes.
  • Mutation check: reverting only WindowsFormatting.hpp to main while keeping the PR's test makes guest_formatting abort with Formatting check failed; restoring it passes. So the NUL %lc/%C fix is exercised on Windows.
  • Not covered: the Linux routing (HasGuestWideFormat) and the positional-argument test are #ifndef _WIN32 and not compiled on Windows. I did not verify Linux.

oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 10, 2026
oneandonlydean added a commit to oneandonlydean/AnyPS5 that referenced this pull request Oct 10, 2026
@oneandonlydean
oneandonlydean merged commit de723ac into boykopovar:main Oct 10, 2026
6 checks passed
SleglJan pushed a commit to SleglJan/AnyPS5 that referenced this pull request Oct 10, 2026
…intf

fix(libc): format guest wide printf arguments on Linux
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants