Skip to content

fix(tests): open scratch streams under a Unicode TEMP on Windows - #13104

Merged
adriadam10 merged 3 commits into
boykopovar:mainfrom
bunbeans2-arch:fix/tests-wide-tmpfile
Oct 30, 2026
Merged

adriadam10 merged 3 commits into
boykopovar:mainfrom
bunbeans2-arch:fix/tests-wide-tmpfile

Conversation

@bunbeans2-arch

Copy link
Copy Markdown
Contributor

What

On Windows, std::tmpfile() returns NULL with errno 22 when %TEMP% contains a character outside the ANSI code page, as it does for a profile like C:\Users\Жанна on a code page 1252 system. There GetTempPathA returns ? in place of the character (#13083). The tests that capture output through a host scratch stream then abort with FileStream: null handle or cannot open a temporary file for stderr.

  • New core/libs/tests/TemporaryFile.hpp: TemporaryFile::Open() creates a uniquely named file under std::filesystem::temp_directory_path() with _wfopen(..., L"w+bxD") (exclusive create, deleted on close, as tmpfile does). Other hosts still return std::tmpfile(). It does not include windows.h.
  • The 15 test files replace each std::tmpfile() with TemporaryFile::Open() (60 calls) and include the header. No other line changes.

core/libs/tests/GuestSyslog.cpp, the 16th test in #13083, is left out: #9929 rewrites the lines around its std::tmpfile() call. It can switch to the helper after #9929 merges.

No production code changes.

Tested

Windows 11 Pro 10.0.22631 (code page 1252), i9-9900K, MSYS2 UCRT64 GCC 16.1.0, Ninja, Release, BUILD_TESTING=ON. The 16 test targets were built on main f6fddd6 and on this branch, and the 16 tests ran with ctest -j 2 -R '^(guest_binary_word|...|guest_filesystem)$'.

TEMP and TMP main f6fddd6 this PR
...\zh_Ж (outside code page 1252) 16 of 16 fail, 3 of 3 runs 15 of 15 changed tests pass, 3 of 3 runs; guest_syslog (unchanged) still fails
...\e_é (inside the code page) 16 of 16 pass 16 of 16 pass
normal profile TEMP 16 of 16 pass 16 of 16 pass

A standalone probe of the header with the same toolchain opened two distinct files under each of those three TEMP values, read back what it wrote, and left no anyps5-test-* file after fclose. After the 3 runs under zh_Ж, that directory held no anyps5-test-* file.

Checklist

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 30, 2026 •

Copy link
Copy Markdown

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.

Pull request Conflicting files (lines on main) Same exports Same new files
PR 12468 core/libs/tests/GuestWideStreamScan.cpp L3
PR 13119 core/libs/tests/FileStreams.cpp L132-133
PR 13531 core/libs/tests/FilePosition.cpp L24-25

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.

Pull request Shared files not compared
PR 7386 core/libs/tests/FileStreams.cpp
core/libs/tests/GuestStdioVariadic.cpp
PR 8150 core/libs/tests/FileStreams.cpp
PR 9371 core/libs/tests/GuestFilesystem.cpp
PR 9863 core/libs/tests/GuestWideStreamScan.cpp
PR 10405 core/libs/tests/GuestStandardStreams.cpp
PR 10620 core/libs/tests/GuestFilesystem.cpp
PR 12057 core/libs/tests/FileStreams.cpp

@MarcZX10 MarcZX10 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 — looks good

The Unicode-safe temporary-file helper is scoped to tests, and the exact-head diff and available Windows evidence show no blocking issue.

What I ran

Reviewed head 9ffb865109811c3c161159ebccce68373eed0d03 against PR base 886e6d752cfb41d8f634ca072f7ca1d9bee98f0d. The merge preview against current upstream/main 08a10d225306ad102b57408e2ef7566bcfb829b2 was clean (tree fe1282aef442de1c69531788583cc7a1ea9ef0b6). Diff and convention checks passed. I also checked the 11 shared-file comparisons flagged by the overlap workflow: each pairwise merge preview with the corresponding current PR head was clean. I did not build or run tests locally.

git merge-tree --write-tree upstream/main refs/remotes/upstream/pr13104
git diff --check upstream/main...refs/remotes/upstream/pr13104
python3 tools/check_conventions.py --base upstream/main --head refs/remotes/upstream/pr13104 --title 'fix(tests): open scratch streams under a Unicode TEMP on Windows' --body <(gh pr view 13104 -R boykopovar/AnyPS5 --json body --jq .body)

Results

Check Result
Current-main merge preview Clean; tree fe1282aef442de1c69531788583cc7a1ea9ef0b6
Diff check Passed; no output
Repository conventions Passed
Flagged overlap comparisons All 11 pairwise merge previews clean
Hosted CI Windows, conventions, intake, eligibility, labels and report passed; Linux and specialized jobs skipped
Windows Unicode-path tests Author-reported: all 15 changed tests passed three runs under an out-of-code-page TEMP; the unchanged guest_syslog test still fails as reported
Unedited local check output
fe1282aef442de1c69531788583cc7a1ea9ef0b6
All conventions checks passed.
7386 e74db94b92ee9a1cabf15c9844e3e26becec2a28
8150 74942c47a4c5d4110013d00c16d8f19277584ef8
9371 cd32cee8d5105eca2986f14d759618216ec4b330
10405 255587cc8fd0180be8aed1787b3f4f2f82adf15e
10620 0cc80c6e6112f059662d4ce5e3ce933b91b4e6d7
11724 f97435f42e9d14b8667bf85648a5bf0de65cecd9
11726 3f845220c35773cda49734692c57e7ec4cb4915d
12057 4720b8de8391887560fbe70f2a2052907fa39b9d
12292 1e18a0e59e6a8fedb1b10d4de2d166d9c585bc26
12468 fd4439edb3c98e3e9cd808ef00f6d9e3487f4bea
12560 21ecce3834c01f0c693d8c1367adf302e3c53f0a

Findings

Blocking

None found.

Non-blocking

GuestSyslog.cpp remains on std::tmpfile() and is explicitly deferred until #9929 is resolved; the PR body accurately identifies that limitation.

Sources

Not verified

I did not compile or run the test suite locally. The Unicode-path tests and Windows build/test results above are reported by the PR author/hosted CI; Linux and macOS results are not provided.

@JJenkx

JJenkx commented Oct 30, 2026

Copy link
Copy Markdown
Contributor

Windows run of this head (9ffb865109), merged onto main 9624d8c6bb (clean merge, local only). Windows 11 Enterprise 10.0.22621, WinLibs GCC 15.2.0 UCRT r7, Ninja, Release, BUILD_TESTING=ON, no Vulkan driver visible. This PR changes tests only, so there is no negative control.

  • 18 of the 19 ctest entries of the touched test executables pass 3 of 3 (ctest --repeat until-fail:3), none skipped.
  • guest_filesystem fails, but at a check that fails the same way on main on this Windows build, not at any line this PR changes. I patched Check locally to record the line: merged-file line 1550, unlink_nid_postfix(danglingDirectoryLink...) == 0, guest errno 13. Unlinking a dangling directory symlink on Windows 11 22621 is fixed separately in fix(libkernel): unlink a dangling Windows directory link #12820 (the CI image, 26100, doesn't hit it). All five hunks this PR makes in GuestFilesystem.cpp are before line 550, so they ran before that check and passed.

No file overlap with #12993, which fixes guest_system_font, exec_arguments and unwrap_self under a non-ASCII TEMP, or with #12996 (VideoOut telemetry and the AGC worker sampler).

AI-assisted: yes (Claude Code).

@malekaifa malekaifa 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 exact current head 0f880fe with an independent Windows Unicode-TEMP reproduction. This host's Windows ANSI code page is 1252. With TEMP=TMP=C:\tmp\zh_Ж, a baseline std::tmpfile() probe returns NULL with errno=22; the exact PR TemporaryFile.hpp compiled with MSVC 14.44 (/std:c++17) opens successfully, writes/reads 'hello', closes successfully, and leaves zero anyps5-test-* files behind. Current-main merge-tree and git diff --check are clean. Compared with MarcZX10's previously approved 9ffb865 head, 14 of the 16 PR files are byte-identical; the two changed files (FileStreams.cpp and GuestStandardStreams.cpp) only absorbed upstream test additions, and their current PR-only hunks remain mechanical std::tmpfile() -> TemporaryFile::Open() replacements. Hosted CI is restarting on this rebase. This adds direct ACP1252 evidence for the issue's out-of-code-page path case; no blocking issue found.

bunbeans2-arch and others added 3 commits October 30, 2026 18:21
On Windows, std::tmpfile() returns NULL with errno 22 when %TEMP%
contains a character outside the ANSI code page, where GetTempPathA
returns '?' in its place. Fifteen tests that capture output through it
aborted. TemporaryFile::Open() opens a unique delete-on-close file under
temp_directory_path() with _wfopen; other hosts keep std::tmpfile().

Part of boykopovar#13083

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… TEMP

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
…de TEMP

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@adriadam10
adriadam10 force-pushed the fix/tests-wide-tmpfile branch from 0f880fe to 1ba27b1 Compare October 30, 2026 17:25
@adriadam10
adriadam10 merged commit c609e61 into boykopovar:main Oct 30, 2026
11 checks passed
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked the diff, the helper (exclusive create, delete on close, EEXIST retry, non-Windows path unchanged) and the Windows runs from @MarcZX10, @JJenkx and @malekaifa.
Added as our own commits on the branch:

  • GuestStandardStreams.cpp: CheckGetcPutc and CheckUngetcEndOfFile, added on main after this branch's base, use TemporaryFile::Open().
  • FileStreams.cpp: the two remaining std::tmpfile() calls from the original base, and the four added by fix(libc): preserve errno on stream scan input exhaustion #13025 (scan input failure errno checks).
    Merged after the full Linux and Windows Build of the new head.

JJenkx added a commit to JJenkx/AnyPS5 that referenced this pull request Oct 31, 2026
… TEMP on Windows

With %TEMP% holding a character outside the ANSI code page, two
Windows tests still abort:

- guest_syslog captures stderr through std::tmpfile(), which returns
  NULL there (boykopovar#13083). It now opens the capture with
  TemporaryFile::Open(), as the other libc tests do since boykopovar#13104.
- guest_kernel_sys_console_identity starts its PS4 child with
  std::system and a command built from directory.string() and
  argv[0]. Both are narrow, so `cd /d` gets '?' in place of the
  character and fails. On Windows the command is now built from
  directory.wstring() and GetModuleFileNameW and run with _wsystem,
  as AsyncLog's child does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
adriadam10 pushed a commit that referenced this pull request Oct 31, 2026
…on Windows

On Windows, std::tmpfile() returns NULL with errno 22 when %TEMP%
contains a character outside the ANSI code page. Thirteen more test
files still called it: the AGC async log, frame dump, PM4 replay and
recorder tests, eight AGC execution tests and the SceNet test. They
now use TemporaryFile::Open(), as #13104 did for the libc tests.

Part of #13083

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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