D621 - The report paired a fault with another thread's calls

Status: measured Date: 2026-09-08

Four decisions built on a pairing nobody checked

D613, D615 and D620 all treat a thread blocked in sceKernelWaitEqueue as the wall in PPSA03416 and PPSA02664. The reason is that the run report prints them together:

! the guest faulted at image+0x39f7c, read of 0xffffffffffffffff
    just before: libkernel::sceKernelWaitEqueue(0x5e2d0000ee40)
    just before: libkernel::scePthreadMutexUnlock(0x400001a2df80) -> 0x0

The call tail is every thread's, and the fault is one thread's. Nothing said which of those lines happened on the thread that died, so they read as a sequence and were treated as one.

They were different threads

The fault now names its own:

! the guest faulted at image+0x39f7c, ..., on guest thread 0x5e2d00000a20
    just before: libSceAgc::sceAgcCreateShader(0x6000007fc538) -> 0x7fff0001  from image+0xf56dd1
    just before: libc::memcpy(0x74000edc0200)
    just before: libc::memcpy(0x74000edc0100)
    just before: libkernel::scePthreadSelf(...) -> 0x5e2d00000a20
    just before: libkernel::sceKernelWaitEqueue(0x5e2d0000ee40)  [another thread]

scePthreadSelf on the faulting thread answers 0x5e2d00000a20, which is the handle the fault reports - the join confirmed from two directions. The event queue was never on that thread.

The actual wall is sceAgcCreateShader answering 0x7fff0001, orbistoun's Unimplemented placeholder, which is still sitting in rbx at the fault three calls later. The guest builds a shader descriptor with two memcpys, asks for a shader, is handed a placeholder, and walks it.

That was in the evidence the whole time, one line below where anybody was looking.

What changed

The shape, again

D616 fixed last_call being used for "what am I inside". This is the same function used for "what was this thread doing", and the fix is the same: two questions were being answered by one function because, single-threaded, they have the same answer.

Both were invisible until a guest ran more than one thread and something blocked. Neither was a wrong calculation - each was a missing distinction, which is the third time this session that has been the finding.