Skip to content

sceKernelPread, sceKernelPwrite and sceKernelFtruncate abort the process on Windows instead of returning errors #2423

Closed

Description

@reyani-dev

On Windows, sceKernelPread and sceKernelPwrite are thin wrappers over the POSIX pread_nid_postfix / pwrite_nid_disambig1_nid_postfix (core/libs/prx/libkernel/File/src/Stdio.cpp). Those throw std::runtime_error on every failure and on a null buffer. The exception can't cross the guest boundary, so the process aborts.

The Linux build's sceKernelPread/sceKernelPwrite (the #else branch) return SceErrorFromErrno(...) instead. That means the same guest call returns an error code on Linux and kills the process on Windows.

ftruncate_nid_postfix / sceKernelFtruncate throw on any host failure on both platforms.

Each case below was run in its own process against current main (Windows 11, WinLibs GCC 15.2.0 r7). Every row aborted with terminate called after throwing ... std::runtime_error:

call Windows expected (Linux build / FreeBSD)
sceKernelPread(9999, buf, 4, 0) abort: pread failed, fd=9999, errno=9 0x80020009 (EBADF)
sceKernelPwrite(9999, buf, 4, 0) abort: pwrite failed, fd=9999, errno=9 0x80020009
sceKernelPread(fd, buf, 4, -1) abort: invalid argument 0x80020016 (EINVAL)
sceKernelPread(fd, NULL, 0, 0) (valid file) abort: invalid argument 0
sceKernelPwrite on an O_RDONLY descriptor abort: pwrite failed, fd=3, errno=5 0x80020009 (EBADF)
sceKernelFtruncate(9999, 0) abort: ftruncate failed, error=9 0x80020009
sceKernelFtruncate on an O_RDONLY descriptor abort: ftruncate failed, error=13 0x80020016 (EINVAL on FreeBSD)

The zero-length pread with a null buffer is valid and should return 0. Some engines probe a descriptor that way.

A likely fix is to give the Windows sceKernelPread/sceKernelPwrite the same early checks and SceErrorFromErrno returns as the Linux branch (NativePread/NativePwrite already exist for both platforms), and to have sceKernelFtruncate return SceErrorFromErrno instead of throwing. I haven't opened a PR for two reasons: #2170 rewrites every line of these functions (descriptor isolation), and intake is currently paused for my account. I'm happy to do it after #2170 lands, or for #2170's author to fold it in.

AI-assisted: yes (the probe was written and run with Claude Code).

Activity

  1. popeee99 commented on Oct 9, 2026

    @popeee99

    Thanks @AchrafReyani for the original report, probes and suggested direction. I independently reproduced your findings on unchanged main (8b393b6e) and prepared a proposed patch with additional regression coverage.

    The patch shares Linux's scalar kernel error-return paths with Windows, separates POSIX ftruncate errno handling from SCE results, and checks Windows handle access/type for the reported permission errors.

    Regression Upstream Patched
    Windows 11, WinLibs GCC 15.2 UCRT r7 17/40 passed 40/40 passed
    Linux/WSL, GCC 15.2 32/38 passed 38/38 passed

    These are assertion counts, not process runs. Baseline failures include the reported exceptions; the harness catches them rather than reproducing a game-process abort. Actual libc/libkernel builds and guest_file_errors, guest_filesystem, guest_file_vector passed on both platforms (3/3 each). The Linux production-source ASan+UBSan regression passed without sanitizer diagnostics.

    Patch, reproduction commands, before/after logs and detailed limitations. Local fix commit: 8fc84d4a.

    No games, macOS, CI, full-emulator or NID-patched-runtime execution, concurrent-I/O validation, or disk-full/query/offset-restoration fault injection. Windows transfers over DWORD remain unsupported. #2029 is still open and modifies the same native helper; reconciliation is required and no combined-branch test is claimed. #2170 is closed without merging.

    Sharing this as reproducible evidence for the existing issue, respecting paused PR intake; no PR opened. AI-assisted with OpenAI Codex.

  2. MarcZX10 commented on Oct 9, 2026

    @MarcZX10
    Contributor

    I compared the proposed patch with the current #2029 head (458e7e42). It cannot be applied as-is: its NativePositioned hunk restores I/O on the shared descriptor and reintroduces the offset race that #2029 fixes. I tested a local integration that preserves ReOpenFile and separate handles, converts Windows scalar sceKernelPread/sceKernelPwrite failures to SCE error returns, and separates sceKernelFtruncate from the POSIX ftruncate_nid_postfix wrapper. Linux libkernel and the existing guest_positioned_io CTest build/pass (1/1), but Windows behavior still needs the reporter’s Windows harness and exact-head CI. Since #2029’s branch is in another contributor’s fork, I have not pushed commits into their branch. Could you and the PR author coordinate permission/ownership for integrating the compatible parts into #2029? The patch also needs a small correction: in its Windows NativeFtruncate, _chsize_s returns an errno value directly, so errno must be set from that value before mapping it.

  3. justdoston commented on Oct 10, 2026

    @justdoston
    Contributor

    Since #2170 and #2029 were closed without merging, here is a version that applies to current main without touching descriptor isolation:

    Branch: https://github.com/justdoston/AnyPS5/tree/fix/windows-file-operation-errors

    • Windows sceKernelPread/sceKernelPwrite get the Linux checks and SceErrorFromErrno returns; a zero-length transfer with a null buffer returns 0.
    • NativePositioned reports ERROR_ACCESS_DENIED as EBADF for reads and writes (a pread on an O_WRONLY descriptor is EBADF on FreeBSD and Linux too), other failures stay EIO. The file-pointer handling is unchanged from main, so the race fix(libkernel): isolate Windows positioned file transfers #2029 addressed is still there, as recorded in TechnicalDebt.
    • ftruncate returns EINVAL for a negative length and for a descriptor without write access (_chsize_s's EACCES is mapped, as @MarcZX100 noted it returns the error instead of setting errno), and passes other host errors to the guest; sceKernelFtruncate returns the kernel error.

    The table's cases are checked in guest_file_vector, which also runs on Windows (guest_directory_entries is Linux-only, so checks there never reach the Windows build).

    Tested: Linux full ctest, no new failures. Not run on Windows: the files cross-compile with MinGW-w64 GCC 16, and under Wine 10.0 (UCRT) WriteFile on an _O_RDONLY and ReadFile on an _O_WRONLY descriptor fail with ERROR_ACCESS_DENIED; Wine's _chsize_s differs from Windows 11 (EINVAL instead of EACCES/EBADF), so the ftruncate cases rely on your Windows measurements.

    AI-assisted: yes. OpenAI Codex wrote the first draft; an AI agent (Claude Code) did most of the work: the review, the fixes, the tests and this comment.

  4. sktharunbalaji13-cmd commented on Oct 10, 2026

    @sktharunbalaji13-cmd
    Contributor

    I validated justdoston/fix/windows-file-operation-errors at 7c706c8822a0d353dacdaa615f5fd6c45effcc44 on Windows 11 using WinLibs GCC 15.2.0.

    The focused guest_file_vector test passed (1/1, 0.16 s). I configured a fresh Release build, built guest_file_vector_tests and its libkernel.prx dependency, and confirmed the binaries were freshly built from this branch. The test exercises the new assertions for invalid descriptors, invalid offsets/lengths, buffer handling, permission errors, and file-content preservation.

    This was a focused Windows run against the branch's pinned base, not a full-suite run or a rebase onto current main. I made no changes to the branch.

  5. added a commit that references this issue on Oct 10, 2026
    1fd723f
  6. added a commit that references this issue on Oct 10, 2026
    c6ee969
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions