9a6c161ba9
ISHIKAWA: el_val_t carries integers AND tagged heap pointers, so "is this a pointer" is undecidable without checking first. That check was a CONVENTION every author had to know rather than a GATE they had to pass through, and looks_like_heap_obj was static -- so every sibling translation unit re-derived it. MEASURED, across the five existing tags geom_of looks_like_heap_obj full guard correct mfld_of looks_like_heap_obj full guard correct el_bin_lookup (uintptr_t)p < 4096 floor only reads 8 bytes BACKWARD el_input_len s ? ... : 0 NULL only strlen's an integer sha256_hex(50000) -> exit 139, SIGSEGV, compiled clean PREDICTIONS AND RESULTS P1 looks_like_heap_obj is static, not exported TRUE P2 each tagged type re-derives the check TRUE P3 at least one is missing guard components TRUE (two are) P6 sha256_hex(<int>) reads out of bounds TRUE P8 routing el_bin_lookup through the gate fixes it FALSE P9 the legitimate hash is unchanged TRUE P11 fixpoint and suites hold TRUE P8 IS THE USEFUL FAILURE. Guarding the tagged lookup changed nothing -- looks_like_heap_obj(49992) correctly returns 0, el_bin_lookup bails, and then el_input_len falls through to strlen() on address 50000. The FALLBACK was the hazard, not the tagged path. A NULL check does not establish that a slot is a pointer. I would have shipped the wrong fix and called it verified. A MEASUREMENT DEFECT, fourth today: my first run of the crash reported exit=0, because $? read head's exit through a pipe rather than the program's. I nearly recorded a segfault as a clean run. Same shape as grepping only parser.el and searching by variable name instead of by operation. AND I PROVED THE HAZARD FROM THE INSIDE. Sixty seconds after diagnosing `let s: String = 42` as an arbitrary-read primitive, I wrote the identical defect into el_await -- dereferencing ->magic off an unvalidated slot -- and only then found the runtime had already made it twice. el_tagged() is now exported in el_runtime.h. Anything that dereferences a slot without passing through it is the defect. 105/105 native, 42/42 integration across eight harnesses, fixpoint ok.