GuestCopyIn_nid_no_patch fell through to a plain memcpy on macOS, so an
unreadable pointer was dereferenced in the host. Read with
mach_vm_read_overwrite and require KERN_SUCCESS and a full copy, the
mirror of the mach_vm_write branch in GuestCopyOut_nid_no_patch and of
CopyGuestBytes.
The test now also checks the order FreeBSD 11.4 uses in sys_setitimer
(sys/kern/kern_time.c:803-808): the new timer is set first and the old
value is copied out afterwards, so a failing copyout reports EFAULT and
leaves the timer armed. The macOS branch has not been run.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Co-authored-by: AdnanKhan-ak47 <[email protected]>
Add agc_copy_guest_bytes, which copies 0 to 80 bytes from each of the eight source offsets with GuestMemory::CopyGuestBytes and checks the copied bytes and the bytes on both sides of the destination. In an ANYPS5_ENABLE_ASAN build with -fsanitize=undefined and UBSAN_OPTIONS=halt_on_error=1 it fails on the misaligned load without the previous commit; other builds check the memcpy path.
The ANYPS5_ENABLE_ASAN build of CopyGuestBytes reads the guest source eight bytes at a time through a volatile const std::uint64_t pointer, but the source has no alignment guarantee, which is undefined behavior. UBSan reports it from agc_driver_pm4, agc_driver_graphics and agc_driver_graphics_maps_fallback: 'load of misaligned address ... for type volatile const uint64_t, which requires 8 byte alignment'. Read through a local alias of std::uint64_t with gnu::aligned(1) and gnu::may_alias instead. GCC still emits one unaligned 8-byte load per word, and builds without ANYPS5_ENABLE_ASAN, which use memcpy, are unaffected.
LookUp is constexpr, so static_assert evaluates it for INT32_MIN and INT32_MAX in a constant expression, where signed overflow is an error. With the previous 32-bit subtraction the test file no longer compiles ('overflow in constant expression'); the existing runtime case for 0x80000000 only showed the overflow under UBSan.
LookUp subtracted the first mapped type, 16, from the UserService keyboard type in 32 bits, which overflows for keyboard types below INT32_MIN + 16; sceConvertKeycodeGetImeKeyboardType passes the type it read from UserService. Compute the index in 64 bits. Every type still maps to the same IME keyboard type, and types outside the table still map to 0.
The test's chain helper built its PCM vector as a local and handed the sampler a
pointer into it, so every render read freed memory. Windows left the old samples
in place; Linux overwrote them and the first case rendered 0.1875 instead of 16.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Take the 16-bit segment size Vita3K and RPCS3 declare. As in Vita3K,
the call answers NOT_INITIALIZED before sceRudpInit and NOT_ACCEPTABLE
while any context exists, and otherwise stores the size.
sceRudpGetMaxSegmentSize keeps the 1410 measured on a PS5: Vita3K leaves
the getter unimplemented, so no source says it reports a stored size.
BunnyFl measured firmware 13.42 libSceNpManager.sprx for the eleven
NpManagerInt getters. They now take the measured arguments and refuse
as measured: user id -1 or a null required pointer gives
INVALID_ARGUMENT, the authorization calls also refuse their value and
mode ranges (0x80550004 for the mode), and the PSNO URI form refuses
its size (0x80550011) and a URI of 0x2000 bytes or more (0x80550005).
Past the checks they keep main's offline signed-out answer for any
request id, and the tests take their request ids from the NpManagerInt
request table.
BunnyFl measured firmware 13.42 libSceNpManager.sprx. The IdMapper
account-id lookups take seven arguments: a request id of 0 or less
gives 0x80553085, then user id -1, a null pointer or a value outside
1 to 1000 gives 0x80553083, and past the checks they answer signed out
as main's offline model does. IdMapper abort and delete refuse a
request id of 0 or less with 0x80553085, and IdMapper requests get a
counter of their own instead of the sceNpCreateRequest pool.
NpManagerInt requests sit in a 64-slot table of their own: the 65th
live request gives 0x80559D05, delete gives 0x80559D0A for an id the
table does not hold, and abort answers from the offline service.
BunnyFl measured both calls in firmware 13.42 libSceNet.sprx, run in an
emulator on the module itself. sceNetInitParam returns 0x80410116 for a
null parameter. The first non-null call copies the first 32 bytes of the
parameter and returns 0, and every later call returns 0x80410110, with a
null parameter and after sceNetTerm too, because the flag is never
cleared. sceNetConfigGetIfFlags returns 0x8041130E for a null flags
pointer before anything else. Both replace throws that stood in for the
unknown answers.
The first successful sceNetInitParam still marks the library initialized,
as sceNetInit does here, because the other calls check it. The module
reads only bit 0 of the stored copy's first word, to raise the pool limit
of sceNetPoolCreate from 32 to 128; that limit is recorded as not
modelled, as sceNetPoolCreate here has none.
The PS5 3.20 export lists have swapcontext in libkernel as well as
libkernel_sys, and on Windows a libkernel import never reaches
libkernel_sys. The assembly entry in UserContext.cpp now is
swapcontext_nid_postfix, and the libkernel_sys jump stub is gone.
Firmware 13.60's libSceSpSysCallWrapper.sprx jumps to libkernel's
scePthreadMutexattrSetprioceiling, which libkernel now implements, so the
wrapper forwards to it like the 47 other wrappers in the library. The
library's debt file held only this entry and is removed.
FPInterpolateF32 and FPInterpolateF16 (v_interp_p1ll/p1lv/p2_f16, v_fma_mix*)
were always emulated in f64, or in 64-bit integers without Float64. Each
interpolation function now computes the result in f32 first and calls the exact
function only when that result is not provably exact.
The f32 path uses no Fma, as Vulkan does not require it to be fused: the product
is a Veltkamp-Dekker two-product, the sum with the base a TwoSum, the error terms
are added with round to odd (Boldo-Melquiond), every operation NoContraction.
It is taken when each input is zero or has a biased exponent in [24, 241] (base
[24, 251]) and the product exponents sum to [174, 377]: every intermediate value
is then a multiple of 2^-126 below 2^126, so none is a denormal a device could
flush and none overflows. A zero result takes its sign from the IEEE rule on the
bits. f16 results are rounded from the f32 bits, on the normal and the subnormal
f16 grid, unless the f32 result is an inexact f16 midpoint; directed f16
rounding keeps the exact path.
agc_driver_interpolation_modes gains 8192 chains of 64 f32 and f16
interpolations over all 32 float modes and a --benchmark of 65536 lanes x 4096
chained interpolations: RTX 4090 Float64 path 10.24 -> 2.05 ms (f32) and
9.91 -> 2.19 ms (f16), integer path 3.58 -> 2.03 / 3.65 -> 2.20 ms; Intel UHD 770
(integer path) 176.6 -> 33.6 / 178.4 -> 56.4 ms.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017SNUYRd7sRKZrMYpquAsnU
The Linux output copied a nonzero r_addend of GLOB_DAT and JUMP_SLOT
relocations unchanged into DT_RELA and DT_JMPREL, while the Windows,
macOS and guest module paths refuse it. The x86-64 psABI computes both
types as S, but glibc before f8587a61892c applies S+A when binding
eagerly, so the result depended on the host glibc and, for JUMP_SLOT,
on the binding mode. The Linux patcher now refuses such an entry in all
three Linux modes with the Windows message and the unrebased r_offset.
Entries with a zero addend are emitted as before.
These wrote their result through the caller's pointer in place, or read
the itimerval of setitimer without a check, so a pointer into unmapped
memory crashed the host. Build the result locally and copy it out with
the checked write (and read the setitimer value with a checked read),
failing with EFAULT as FreeBSD 11.4 does: copyout in sys_gettimeofday
(sys/kern/kern_time.c:646 and 651) and sys_getitimer (kern_time.c:745),
copyin (kern_time.c:803) and copyout (kern_time.c:808) in sys_setitimer.
getrlimit and getrusage are left to #8986 and #8988, which cover the same
family for those two calls.
Builds on fix/output-structs-efault, which adds GuestCopyOut_nid_no_patch.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
The 2026-10-21 split PRs added Export.cpp stub files to seven libraries
that have their own CMakeLists.txt, so core/libs/CMakeLists.txt never
adds Export.cpp for them and no target compiled the 101 stubs. A title
that imports one fails to load instead of throwing on the call.
Ngs2, Ngs2.native and AvPlayer.native build with hidden visibility, so
their stub files also need default visibility. libSceNgs2 already
compiled PendingExports.cpp, but its 6 stubs stayed local.