You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
libkernel: writing to a pipe whose reader is closed returns EINVAL on Windows instead of EPIPE; fix branch ready #5246
On Windows, write, writev, sceKernelWrite and sceKernelWritev to a pipe whose read end has been closed fail with EINVAL instead of EPIPE. The host C runtime maps ERROR_NO_DATA (232) to EINVAL, and FreeBSD 11.4 pipe_write returns EPIPE. A guest that treats EPIPE as "the reader went away" (the usual way a writer ends cleanly) sees a generic invalid-argument error instead.
Fix branch: https://github.com/husseinkad/AnyPS5/tree/fix/libkernel-pipe-write-epipe (one commit on a recent main: File/src/Open.cppNativeWrite, the TransferIovecs error path in File/src/Stdio.cpp, and the new test tests/GuestPipeClosedWrite.cpp, registered as guest_pipe_closed_write). ERROR_NO_DATA is now remapped to EPIPE in both places. NativeTransfer is left alone because #4885 changes it.
Checks:
The new test fails on main (abort) and passes with the change; guest_file_vector, guest_kernel_fcntl and guest_dup pass.
Probed through the guest exports against main: a write of 1, 4096, 4097 bytes and 1 MiB, and writev with 1 to 4 iovecs (including zero-length ones), now give EPIPE (32) for blocking and nonblocking pipes, and sceKernelWrite/sceKernelWritev return 0x80020020. A 1 MiB write blocked on a 4096-byte pipe wakes with EPIPE when the reader closes (with two blocked writers main returned EPIPE for one and EINVAL for the other; now both get EPIPE), with no hangs. Unchanged against main: a full pipe (EAGAIN or blocking), a write to the read end and to a closed or invalid fd (EBADF), and writes to a regular file, a read-only file and a socket. A direct probe through both ucrtbase.dll and msvcrt.dll shows the same EINVAL with _doserrno 232, which matters because local toolchains and CI use different C runtimes.
Not covered: no SIGPIPE is raised on Windows (already recorded in docs/dev/debt/libkernel.md); a write that is part done when the reader closes returns EPIPE instead of the partial count through the single-buffer path (the iovec path does return the count); the check reads _doserrno without clearing it first. A zero-length write and a zero-length writev on a broken pipe return 0 where FreeBSD returns EPIPE, and a nonblocking writev on a full pipe gives ENOSPC rather than EAGAIN; both are the same on main. Only Windows was built and run.
Implemented in #5265. I built guest_pipe_closed_write_tests on Linux and ran guest_pipe_closed_write; the test passed (1/1). The Windows-specific EPIPE mapping was not executable in my Linux environment. The implementation also guards the Windows-only error check so it does not affect Linux compilation.
Closing: no title is known to reach this, and functions are only changed when a title needs them. #5265 is closed for the same reason. If a title stops on or misbehaves because of it on current main, comment here with the title ID and the log line.
Activity
MarcZX10 commentedon Oct 13, 2026
Implemented in #5265. I built
guest_pipe_closed_write_testson Linux and ranguest_pipe_closed_write; the test passed (1/1). The Windows-specific EPIPE mapping was not executable in my Linux environment. The implementation also guards the Windows-only error check so it does not affect Linux compilation.oneandonlydean commentedon Oct 14, 2026
Closing: no title is known to reach this, and functions are only changed when a title needs them. #5265 is closed for the same reason. If a title stops on or misbehaves because of it on current main, comment here with the title ID and the log line.