Skip to content

fix(libkernel): report O_RDWR from F_GETFL on both ends of a pipe - #8544

Merged
oneandonlydean merged 3 commits into
boykopovar:mainfrom
Retr0G28:fix/fcntl-getfl-pipe-rdwr
Oct 23, 2026
Merged

oneandonlydean merged 3 commits into
boykopovar:mainfrom
Retr0G28:fix/fcntl-getfl-pipe-rdwr

Conversation

@Retr0G28

@Retr0G28 Retr0G28 commented Oct 20, 2026 •

Copy link
Copy Markdown
Contributor

What

fcntl(F_GETFL) on a pipe end reported O_RDONLY for the read end and O_WRONLY for the write end, because the access mode came from the host, where pipe ends are one-way. FreeBSD 11 pipes are bidirectional: kern_pipe opens both ends with finit(..., FREAD | FWRITE, ...) (sys/kern/sys_pipe.c), and kern_fcntl builds F_GETFL from OFLAGS(fp->f_flag) (sys/kern/kern_descrip.c), so both ends report O_RDWR.

The guest descriptor table now marks descriptors created by pipe. The mark follows dup, dup2 and F_DUPFD with the shared status flags, an entry made by open replaces it, and close drops it. F_GETFL reports O_RDWR for a marked descriptor and still asks the host for every other descriptor, so a FIFO opened with O_RDONLY keeps reporting O_RDONLY, as on FreeBSD. The sentence about this gap is cut from the fcntl entry in docs/dev/debt/libkernel.md.

Test changes:

  • guest_kernel_fcntl (PipeFlagsRoundTrip) now expects O_RDWR on both ends, with and without O_NONBLOCK, and on an F_DUPFD copy of the write end.
  • guest_dup now expects O_RDWR | O_NONBLOCK in its shared-status-flags case.

Tested

Windows 11, WinLibs MinGW-w64 GCC 15.2.0 r7, CMake + Ninja, Release, -DBUILD_TESTING=ON, on main 77e3121.

  • Before the fix, guest_kernel_fcntl with the new expectations fails (exit 0xc0000409 from the failed Require). With this PR it passes.
  • ctest -R "fcntl|pipe|dup|poll|select|kqueue|stdio|descriptor|socket" -E "^agc_": 40 of 40 pass when run serially.
  • Every guest_ test (547): the only failures that remain when run alone are guest_module_dir and guest_module_identity. They fail the same way on main on this machine (Windows Defender blocks a file they generate, WinError 225).
  • python tools/check_conventions.py --base origin/main reports no errors. The one warning is the existing length of the fcntl debt entry, which this PR shortens.
  • Linux: @xXPBSXx ran the PR head on WSL2 Ubuntu 24.04 (GCC 13.3.0): guest_dup and guest_kernel_fcntl pass, and both fail with main's DescriptorControl and Stdio.cpp (comment below). Not run on bare-metal Linux.
  • No title or homebrew run.

Overlap: tools/pr_overlap.py could not compare some open PRs. I checked the ones that touch the same code files (#7121, #6977, #6044, #5021, #6936, #7201, #7530). None changes the access mode F_GETFL reports for a pipe. The rest touch only other lines of docs/dev/debt/libkernel.md.

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

FreeBSD 11's kern_pipe opens both ends with FREAD | FWRITE, so F_GETFL
reports O_RDWR on each. The host pipe ends are one-way, so the access
mode came back as O_RDONLY and O_WRONLY. Descriptors made by pipe() are
now marked in the guest descriptor table, the mark follows dup, dup2 and
F_DUPFD, and F_GETFL reports O_RDWR for them.
@github-actions

github-actions Bot commented Oct 20, 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 9019 core/libs/prx/libkernel/File/include/DescriptorControl.hpp L15
core/libs/prx/libkernel/File/src/DescriptorControl.cpp L117, L567-568

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 4630 docs/dev/debt/libkernel.md
PR 5021 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 6044 core/libs/tests/GuestDup.cpp
core/libs/tests/GuestKernelFcntl.cpp
PR 6149 docs/dev/debt/libkernel.md
PR 6740 docs/dev/debt/libkernel.md
PR 6830 docs/dev/debt/libkernel.md
PR 6936 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 7049 docs/dev/debt/libkernel.md
PR 7088 docs/dev/debt/libkernel.md
PR 7105 docs/dev/debt/libkernel.md
PR 7121 core/libs/prx/libkernel/File/include/DescriptorControl.hpp
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 7149 docs/dev/debt/libkernel.md
PR 7201 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 7509 docs/dev/debt/libkernel.md
PR 7565 docs/dev/debt/libkernel.md
PR 7653 docs/dev/debt/libkernel.md
PR 8010 docs/dev/debt/libkernel.md
PR 8520 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 8553 docs/dev/debt/libkernel.md
PR 9074 docs/dev/debt/libkernel.md
PR 9133 docs/dev/debt/libkernel.md
PR 9199 docs/dev/debt/libkernel.md
PR 9256 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
core/libs/tests/GuestKernelFcntl.cpp
docs/dev/debt/libkernel.md
PR 9284 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9293 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9297 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9302 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9423 core/libs/prx/libkernel/File/src/Stdio.cpp
PR 9557 core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 9561 core/libs/prx/libkernel/File/include/DescriptorControl.hpp
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
core/libs/prx/libkernel/File/src/Stdio.cpp
core/libs/tests/GuestKernelFcntl.cpp
docs/dev/debt/libkernel.md
PR 9566 core/libs/prx/libkernel/File/include/DescriptorControl.hpp
core/libs/prx/libkernel/File/src/DescriptorControl.cpp
docs/dev/debt/libkernel.md
PR 9575 docs/dev/debt/libkernel.md
PR 9669 docs/dev/debt/libkernel.md
PR 9693 core/libs/prx/libkernel/File/src/Stdio.cpp
docs/dev/debt/libkernel.md
PR 9823 core/libs/prx/libkernel/File/src/Stdio.cpp

@xXPBSXx

xXPBSXx commented Oct 21, 2026

Copy link
Copy Markdown
Contributor

Linux data point for 2d1fa5aea5: WSL2 Ubuntu 24.04 (virtualised kernel, not bare-metal Linux), GCC 13.3.0, Release, BUILD_TESTING=ON, PR head alone (not merged onto main).

  • With the PR: ctest -R '^(guest_dup|guest_kernel_fcntl)$' passes 3 of 3 (both tests).
  • With DescriptorControl.hpp, DescriptorControl.cpp and Stdio.cpp (libkernel/File) restored to the merge-base (new test cases kept): both fail (Subprocess aborted).
    Not tested: macOS, Windows, a title run.
    AI-assisted (Claude Code).

@DavidSamir

Copy link
Copy Markdown
Contributor

Hi @Retr0G28, a merge-order note: my #9557 (pipe SIGIO owner) and #9561 (O_FSYNC) edit the same fcntl row of docs/dev/debt/libkernel.md as this PR, and they conflict in that file only. Proposal: no dependency either way; whichever merges second keeps every sentence. Does that work for you? I'll record it in their checklists.

AI-assisted: yes

@Retr0G28

Copy link
Copy Markdown
Contributor Author

@DavidSamir Yes, that works for me: no dependency either way, and whichever of us merges second rebases and keeps every sentence of the fcntl row. I checked with git merge-tree: this PR conflicts with #9557 and #9561 only in that row of docs/dev/debt/libkernel.md.

@oneandonlydean oneandonlydean self-assigned this Oct 22, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 23, 2026
@oneandonlydean
oneandonlydean merged commit 85f2f2d into boykopovar:main Oct 23, 2026
10 checks passed
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.

4 participants