Skip to content

fix(libc): share delete access on a stream reopened with freopen on Windows - #5033

Closed
milescoviello wants to merge 3 commits into
boykopovar:mainfrom
milescoviello:carry/freopen-delete-sharing-windows-5031
Closed

milescoviello wants to merge 3 commits into
boykopovar:mainfrom
milescoviello:carry/freopen-delete-sharing-windows-5031

Conversation

@milescoviello

Copy link
Copy Markdown
Contributor

What

Fixes #5031. Carries @DavidSamir's fix branch from that issue (DavidSamir:fix/libc-freopen-delete-sharing-windows, 9203b42ba, three commits), keeping the commits and their authorship. The fix and the test cherry-pick onto current main without changes; the debt commit needed one conflict resolved, because #4918's _Unwind_Context entry landed next to the line it edits, and both entries are kept as they are.

On Windows, while a stream that went through freopen held a file, rename of that file failed with EIO and remove with EBUSY, and sceKernelRename on it failed too. With a stream from fopen or a descriptor from sceKernelOpen both work, as on the console and in the Linux build. fopen opens the file itself with FILE_SHARE_DELETE (#4090), but freopen hands the name to _wfreopen, which opens it without that share mode. docs/dev/debt/libc.md recorded the gap. A title that reopens its log or save file with freopen and then rotates or replaces it gets the error.

_wfreopen still does the reopening, so the stream object, its buffer, its mode and its descriptor number stay as they are. After it succeeds, ShareReopenedFile opens the same file again with read, write and delete sharing and the access the mode asks for, as OpenNative does for fopen. It then moves the stream's descriptor onto that handle with _dup2, which closes the handle _wfreopen made. The a modes keep _O_APPEND, and descriptors 0 to 2 keep their Win32 standard handle (#4640). If the second open fails, freopen closes the stream and returns null with that error, as when the reopening itself fails. Linux is unchanged.

The commits are:

  • the fix, in FileAndHeap.cpp;
  • a sequence in file_streams: fopen in wb, freopen in ab, then freopen in r+b, after which rename and remove on the name succeed while the stream is open and the stream still reads back both writes;
  • the debt entry describing how a reopened stream gets its handle.

Tested

  • From the issue, on Windows 11, WinLibs MinGW-w64 GCC 15.2.0, Release:
    • With main's FileAndHeap.cpp, file_streams fails. With the fix it passes 5/5, and the related stream, file and descriptor tests pass 3/3.
    • A 127-line probe over eight modes matches main except for the renames and removes. It matches the Linux build on 125 lines; the two that differ differ the same way with main's libraries.
    • 3000 reopens leave the handle count unchanged. Probes of the descriptor, stream, file, time, thread, flock, pipe and fdopen functions are unchanged.
    • freopen costs about 40 µs more, because it opens the file twice.
    • Twelve catalog titles end the same way with both sets of libraries.
    • Full ctest: 1037/1039. The two failures are GPU tests that fail the same way on main on that machine.
  • Added for this carry, on Linux: Ubuntu 24.04, GCC 13.3 (CI's compiler), Release with CI's configure flags, on main 2a2a3dc:
    • The build is clean, file_streams passes 20/20, and all 334 guest_* tests pass in two runs.
    • The changed code is Windows only, so this shows only that the Linux build is unaffected and that the new test sequence holds there.
    • A MinGW-w64 GCC 13 -fsyntax-only -Wall -Wextra compile of FileAndHeap.cpp and FileStreams.cpp is clean.
    • I could not run Windows myself.
  • tools/check_conventions.py --base upstream/main passes.

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 (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Unblocks: none
  • AI-assisted: yes

🤖 Generated with Claude Code

@github-actions

github-actions Bot commented Oct 13, 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
#4822 docs/dev/debt/libc.md L47

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Closing: no title is known to reach this. With the queue at 700+ open PRs, please hold off on new PRs that don't name a title needing the change until it's down. If a title stops on this on current main, reopen with the title ID and the log line.

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.

libc: a file held by a stream reopened with freopen cannot be renamed or removed on Windows; fix branch ready

3 participants