Skip to content

fix(libc): fail scanf and ungetc on write-only streams on Linux as FreeBSD does - #15768

Open
AlexWhitehouse wants to merge 1 commit into
boykopovar:mainfrom
AlexWhitehouse:fix/libc-linux-scanf-write-only-error
Open

AlexWhitehouse wants to merge 1 commit into
boykopovar:mainfrom
AlexWhitehouse:fix/libc-linux-scanf-write-only-error

Conversation

@AlexWhitehouse

Copy link
Copy Markdown
Contributor

What

On Linux, guest fscanf, vfscanf, scanf and vscanf on a stream open only for writing returned EOF with EBADF but left the error indicator clear. #14878 fixed reads on such streams for Windows and recorded this Linux gap in docs/dev/debt/libc.md:

  • Cause: the glibc branch of FileStream::SwitchToReadingUnlocked (core/libs/prx/libc/include/FileStream.hpp) let a non-readable stream through to glibc's __vfscanf_internal. That function rejects _IO_NO_READS without setting _IO_ERR_SEEN.
  • Source: FreeBSD 11.4's __srefill sets errno = EBADF and __SERR, then returns EOF.

Change:

  • Reads: the glibc branch of SwitchToReadingUnlocked now fails a stream that __freadable rejects exactly as the Windows branch does: errno 9, the guest error indicator, and false. Every read path already returns on a failed switch, so fscanf and vfscanf now report EBADF with the error indicator, like fread, fgetc, getc_unlocked and fgets already did through glibc's underflow. Update streams take the same path as before.
  • Pushback: FileStream::OpenForReading gains a glibc branch (__freadable). As a result, ungetc and ungetwc on a write-only stream return EOF without setting errno or the error indicator, as FreeBSD 11.4's __ungetc does ((fp->_flags & __SRD) == 0 and no __SRW) and as Windows has since fix(libc): fail reads on a write-only stream with EBADF on Windows #14878. Before, glibc pushed the character back onto the write-only stream.
  • Other hosts: the Windows and macOS code is unchanged.
  • Debt: the Linux clause of the "Reads on a write-only stream" entry is resolved. The entry now records only that macOS is expected to follow BSD stdio and has not been run.

Tested

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
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

…eeBSD does

On Linux, fscanf, vfscanf, scanf and vscanf on a stream opened only for
writing returned EOF with EBADF but left the error indicator clear:
SwitchToReadingUnlocked let the stream through to glibc's
__vfscanf_internal, which rejects _IO_NO_READS without setting
_IO_ERR_SEEN. FreeBSD 11.4's __srefill sets EBADF and __SERR. The glibc
branch now fails an unreadable stream the way the Windows branch does
since boykopovar#14878: errno 9, the guest error indicator, and false.

OpenForReading gains a glibc branch (__freadable), so ungetc and ungetwc
return EOF on such a stream without touching errno or the error
indicator, as FreeBSD's __ungetc does and as Windows already did.
Before, glibc pushed the character back onto the write-only stream.

file_streams now checks fscanf, vfscanf, fgetwc, ungetc, ungetwc and
clearerr on write-only streams on every host, not only on Windows.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 6, 2026
@AlexWhitehouse
AlexWhitehouse force-pushed the fix/libc-linux-scanf-write-only-error branch from efe547e to 02e2d8d Compare November 6, 2026 16:59
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Nov 6, 2026

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant