D639 - Twenty blank pages nobody mentioned
Status: measured Date: 2026-09-09
A fault with three null registers and no explanation
PPSA21564 runs half a million calls at 100% standing - two calls on stubs out of 500,260 - and dies in its own module's static initialisation:
! the guest faulted at the title's own modules+0x7af792, read of 0x38
read of 0x38 is a null pointer plus an offset
rax=0x0 rcx=0x0 rdi=0x0 … r12=0x720000007000 r13=0x720000007000
just before: libc::__cxa_guard_release(0x40000e2d2788) -> 0x0
just before: libc::__cxa_guard_acquire(0x40000e2d2788) -> 0x1
__cxa_guard_acquire answering 1 means
run the initialiser, and the tail before it is hundreds of
libc::strcmp calls from one site, all against the same
string, all non-zero: a linear search by name that never matches, then a
null.
r12 and r13 printed as bare numbers.
0x7200_0000_0000 is SUGGESTED_DATA_BASE -
storage for imports that name data rather than
functions (D323) - and nothing in the report said so.
Twenty of them, and most are C++ vtables
libc _ZTVN10__cxxabiv120__si_class_type_infoE [data]
libc _ZTVN10__cxxabiv117__class_type_infoE [data]
libc _ZTVSt9bad_alloc [data]
libc _ZSt21_sceLibcClassicLocale [data]
libc _Stdout / _Stderr, libkernel __stack_chk_guard, … 20 in all
Each is served as one zeroed page (D307). A zeroed
vtable is a table of null function pointers, so the first virtual call
through one reads null and dies at a small offset - which is what this
title does, at +0x38.
Whether that is this fault's cause is not asserted here. What is asserted is that the run handed the guest twenty blank pages and said nothing about any of them, so nobody reading the fault could connect the two.
Three omissions, one after another
Naming them took three fixes, and each was invisible behind the one before it:
- The region is not one of the five the fault handler
knows (image, stubs, stack, guest mappings, title modules), so
locatereturned nothing and the address printed bare. - The reverse lookup did not exist.
DATA_SYMBOLShas been published as name-to-address since D344; nothing went the other way.data_symbol_atdoes, by exact page - the blocks are contiguous, so a nearest-preceding search would name the block before a gap as though it owned the address. - The pages were never published as readable. The register annotator only emits a line for an address whose bytes it can read, so with the first two fixed it still printed nothing. Exactly the omission D593 found for the title's own modules, in the region beside them.
r12 -> data f7uOxY9mM1U#r#n+0x0 = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
Sixteen zero bytes, named as a data import.
What it still cannot say
The key is the raw import string - the encoded NID -
not the decoded symbol. That is deliberate elsewhere and load-bearing:
data_symbol("optarg") is how an implementation finds the
guest global it owns (D344), so re-keying the map would break the lookup
it exists for. A separate display name is the fix and it is not
done.
data f7uOxY9mM1U#r#n is worse than
data _ZTVSt9bad_alloc and enormously better than
0x720000007000, which is what it said this morning.