D218 - Two experiments that eliminated four things and confirmed nothing

decided · 2026-08-24 · directed by the user, continuing the wall work from D217

Two mechanisms built, one wall swept with each, and the honest result is that both leading hypotheses are now dead. Recorded because a negative result nobody writes down gets re-run.

The map shape, and an experiment that was underpowered

PPSA04263 spends 99.9% of every call walking the memory map and rejecting it - 852 million queries in twenty seconds, never reaching sceKernelAllocateDirectMemory at all. Three answers had been swept and changed nothing: the return code, the third structure field, and whether the buffer is cleared. The map itself had never been anything but one free region starting at zero.

That is worse than an untried option. A guest hunting for a region matching some criterion cannot distinguish "wrong value" from "wrong shape" when there is one region to look at, so the third-field sweep proved less than it was read as proving - the same shape as D187, where an ok sweep reported no change because the functions under test never saw it.

Settings::map_shape (whole, reserved-low, fragmented) is data in the run configuration, not a rebuild, and defaults to what every earlier measurement was taken against so changing it is deliberate.

Result: the guest walks any map correctly and rejects it anyway. Given four regions - taken [0,512M), free [512M,2.5G), taken [2.5G,3.5G), free [3.5G,8G) - it queried 0, 0x20000000, 0xA0000000, 0xE0000000, 0x200000000, then restarted at zero. Every region, in order, correct. Map shape is eliminated.

And one thing it cannot settle, which I nearly claimed it did. A contiguous map cannot distinguish end from start + size in the second field, because each region begins where the last ended - so a guest feeding back the previous end produces identical offsets under either layout, whatever the shape. Settling that needs a map with a gap in it, not one with more regions.

Planting a value, because a stub can only change what a function answers

A stub policy sets a return value. Nothing could set a side effect - and both walls had been narrowed to "an out-parameter nobody wrote" (D217). The only mechanism for a side effect is a guest_module! declaration keyed by a name, and the function on the biggest wall has none that any source reaches (D213).

ORBISTOUN_WRITE=<import>:<slot>:<value> plants a u64 at the address in an argument before the import answers. It resolves an import the way forced dumps do, so an unnamed function can be named by its hash. Diagnostic standing, like the stack poison (D185): in the environment because a question is asked once rather than configured.

Three things it does that matter more than the write itself:

Result: arg0 and arg5 are not it. Both point into the stack, both were planted with 0x11000000, both landed (1 planted, 0 refused), and the fault stayed at 0xfffe0 exactly. The guest's zero base does not come from either.

Where that leaves the wall

Eliminated, all by measurement: the stub return (arithmetic on the observed fault address), unwritten stack (the poison), arg0's target, and arg5's target. memalign was ruled out earlier and is implemented and returning real allocations.

So the guest gets a zero from somewhere this session has not found, and the out-parameter reading - which was the only surviving explanation an hour ago - is now itself in trouble. That is a worse position to be in and a better thing to know.

Declaration by NID was not built. It was conditional on the out-parameter hypothesis surviving, and it did not. Building a mechanism to implement unnamed functions in order to fill an out-parameter nothing has shown to exist would be speculation, which is what principle 11 refuses.