Skip to content

fix(libSceNet): count only datagram bytes in sceNetIoctl FIONREAD on macOS - #10628

Open
maximilianfv wants to merge 1 commit into
boykopovar:mainfrom
maximilianfv:fix/libscenet-macos-datagram-fionread
Open

maximilianfv wants to merge 1 commit into
boykopovar:mainfrom
maximilianfv:fix/libscenet-macos-datagram-fionread

Conversation

@maximilianfv

@maximilianfv maximilianfv commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

What

On macOS, FIONREAD on a datagram socket counts more than the queued payload, so sceNetIoctl(socket, FIONREAD) on a sceNetSocket UDP socket reported 37 after one 5-byte datagram, where guest_sce_net expects 5, as Linux reports. On macOS, sceNetIoctl now asks a non-stream socket for SO_NREAD, the size of the next datagram, and keeps ioctl(FIONREAD) for stream sockets. libkernel's own sockets already do this on macOS (QueuedBytes in libkernel/Socket/src/Udp.cpp, from #7850 by mugurc), and docs/dev/debt/libkernel.md records it. The sceNetIoctl entry in docs/dev/debt/libSceNet.md now says the same for macOS. Linux and Windows are unchanged.

Prior art: iamthehimansh made the same change to sceNetIoctl in commit b2c0e64 (2026-10-23) of the closed macOS port #8658, so he is credited as co-author on the commit. That commit is not in the PRs #8658 was split into (#10362, #10419). The two differ in small ways: that version sends only NET_SOCK_DGRAM sockets to SO_NREAD and has a code comment and no debt entry; this one sends every non-stream socket and updates the debt entry. #7201 (marion909) and #7332 (ycarogabriel-lgtm) use SO_NREAD only in libkernel's ioctl, not in libSceNet. #9932 and #9948 (ntamas94) read FIONREAD in sceNetGetSockInfo, a different function.

What the console reports is a separate question: #9932 (ntamas94) measured on a PS4 Pro that sceNetGetSockInfo's receive queue length counts each queued datagram's payload plus 16 bytes, as FreeBSD 11.4's receive buffer does. So this change matches neither the console nor plain macOS; it follows libkernel's sockets and the test. The debt entry now says so.

Tested

Apple M1 Pro, macOS 27.0.1, x86_64 build under Rosetta 2. main alone does not build on macOS, so I tested in a tree made of mugurc's macOS series (ci/macos-series-2, 27e9689) merged with main at 1e20650, plus other macOS fixes that are not yet open PRs and #9231 (7c5d973). Only this change differed between the two runs.

ctest -R '^(guest_sce_net|guest_inet_address|guest_net_.*|guest_datagram_.*|net_dontwait_.*|guest_socket_error|guest_udp)$' (21 tests): 20 pass both with and without this change. guest_sce_net aborts in both runs, at a different check each time:

  • Without this change it stops at GuestSceNet.cpp:845. After one 5-byte sceNetSendto to itself and a readable poll, sceNetIoctl(socket, 0x4004667f, ...) gives 37 where the test expects 5 (value read with lldb at the abort).
  • With it, that check passes and the test stops later at GuestSceNet.cpp:1930: sceNetResolverStartNtoa6 of "127.0.0.1" must fail with 0x804101E1. This is a separate resolver gap.

I found both stops with lldb on a -O0 rebuild. The test reaches the FIONREAD check only with #9231 (Gonic0) applied, because #9231 fixes an earlier stop at GuestSceNet.cpp:175. This change does not need #9231's code; only the test needs it to get that far.

Not tested on Linux or Windows; the code there is unchanged.

After #10572 merged I rebased onto main fccc63319d. Only the debt-file context changed, the code is byte-identical, and I did not re-run the tests.

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 (fix(libSceNet): print the console's line for a negative sceNetUsleep #10572 has merged and this branch is rebased onto it)
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed exact head 57333d34904a5f01b8f2b0d480265960cf3ea542. The macOS-only branch preserves stream FIONREAD behavior and uses SO_NREAD for non-stream sockets, matching the platform-specific mismatch reproduced in the PR body and the existing guest assertion for a 5-byte datagram. Linux and Windows code paths are unchanged. The debt text now records the platform behavior and distinguishes the PS4 Pro sceNetGetSockInfo measurement from this sceNetIoctl call.

git diff --check upstream/main...HEAD and python3 tools/check_conventions.py --base upstream/main --head HEAD pass on this exact head. Hosted eligibility, conventions, intake, and labels pass; product test jobs were skipped. The macOS 21-test run and before/after debugger evidence are author-reported; I did not independently run macOS. I found no blocking issue in this focused platform fix.

@Gonic0

Gonic0 commented Oct 24, 2026

Copy link
Copy Markdown

Checked the host side on an M5 Pro, macOS 27.2 (26B5086k), with a small C program on a loopback UDP socket, built both x86_64 (Rosetta 2) and arm64. Both builds print the same numbers:

Queue FIONREAD SO_NREAD
empty 0 0
one 5-byte datagram 37 5
5 + 10 + 20 bytes 131 5
after one recv (10 + 20 left) 94 10
one 0-byte datagram 32 0
0-byte, then 7-byte 71 0

So on 27.2 too, FIONREAD is the payload plus 32 bytes per queued datagram (the 37 you saw), and SO_NREAD is the size of the next datagram, which is what Linux's FIONREAD reports. That includes the Linux edge case #9932 describes: a 0-byte datagram at the head reads as 0 even with more data behind it, so macOS now behaves like Linux there as well.

libSceNet/Export.cpp at 57333d3490 compiles on this machine (Apple clang 21.0.0, x86_64 Release), with no warnings in the changed lines under -Wall -Wextra. I didn't run guest_sce_net myself; that part rests on your run.

AI-assisted: yes

@github-actions

github-actions Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

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 5836 core/libs/prx/libSceNet/Export.cpp
docs/dev/debt/libSceNet.md
PR 7201 core/libs/prx/libSceNet/Export.cpp
PR 9932 core/libs/prx/libSceNet/Export.cpp
docs/dev/debt/libSceNet.md
PR 9948 core/libs/prx/libSceNet/Export.cpp
docs/dev/debt/libSceNet.md
PR 11341 core/libs/prx/libSceNet/Export.cpp

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up on the new overlap check at exact head 57333d34904a5f01b8b2d0b480265960cf3ea542: I manually compared the shared docs/dev/debt/libSceNet.md hunk with #10572. git merge-tree --write-tree upstream/pr/10572 upstream/pr/10628 reports a content conflict in that file: both PRs edit the adjacent sceNetUsleep / sceNetIoctl entries in one hunk. The two code changes are distinct, and the conflict is straightforward to resolve by retaining both updated entries, but the PRs still need an agreed merge order and the dependent PR should record Depends on: #N as required by CONTRIBUTING. The current checklist says Depends on: none.

Please coordinate with #10572's author and record the agreed order/dependency. My earlier approval covered the implementation; this review requests changes only for the unresolved documentation merge coordination. The newly posted macOS measurements on #10628 are useful additional host evidence.

@maximilianfv

Copy link
Copy Markdown
Contributor Author

Thanks. Depends on: #10572 is now in the checklist: the conflict is only the neighbouring sceNetUsleep / sceNetIoctl debt entries, so this PR waits for #10572 and I rebase it afterwards, keeping both entries.

AI-assisted: yes

@MarcZX10 MarcZX10 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Follow-up on exact head 57333d34904a5f01b8f2b0d480265960cf3ea542. The merge-order blocker is resolved: #10572's author confirms it lands first, and this PR now records Depends on: #10572 and will rebase to retain both debt entries. My prior code review remains applicable: the macOS-only path uses SO_NREAD for non-stream sockets while preserving stream FIONREAD; Linux and Windows are unchanged. The author reports 20 of 21 focused tests pass in both runs; the one guest_sce_net stop is a separate resolver expectation, and the target FIONREAD assertion passes only with this change. Hosted policy checks pass and product builds were skipped. I did not independently run the macOS test suite. No blocker remains.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
…macOS

On macOS, FIONREAD on a datagram socket counts more than the queued
payload, so after one 5-byte datagram sceNetIoctl reported 37.
libkernel's sockets already ask a macOS datagram socket for SO_NREAD,
the size of the next datagram, instead; do the same for sceNetSocket
sockets that are not streams.

Co-authored-by: Himansh Raj <67262056+iamthehimansh@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maximilianfv
maximilianfv force-pushed the fix/libscenet-macos-datagram-fionread branch from 57333d3 to 3d20b5e Compare October 25, 2026 06:18
@maximilianfv

Copy link
Copy Markdown
Contributor Author

Rebased onto main fccc63319d now that #10572 has merged (new head 3d20b5e4c2). The only conflict was in docs/dev/debt/libSceNet.md. I kept #10572's sceNetUsleep entry from main and this PR's sceNetIoctl entry, and neither text changed. The core/libs/prx/libSceNet/Export.cpp hunk is byte-identical to the approved 57333d3490. tools/check_conventions.py --base origin/main passes. I did not rerun the tests on the new base.

AI-assisted: yes

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 25, 2026
@adriadam10 adriadam10 self-assigned this Oct 26, 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.

4 participants