a slot must be validated before it is dereferenced
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.
This commit is contained in:
@@ -888,6 +888,7 @@ el_val_t engram_age_field_catchup(void);
|
||||
el_val_t engram_chrono_persist_tick(void);
|
||||
el_val_t engram_chrono_tick(void);
|
||||
el_val_t engram_boundary_beat(el_val_t op_name, el_val_t construct);
|
||||
int el_tagged(el_val_t v, uint32_t magic); /* the gate: validate a slot BEFORE dereferencing it */
|
||||
el_val_t el_seam_run(el_val_t fn_name, el_val_t phase, el_val_t result); /* runtime construct seam */
|
||||
el_val_t el_seam_wrap(el_val_t fn_name, el_val_t (*body)(void*), void* env); /* runtime invocation control */ /* API-reshape decorator-seam auto-emit; construct = the decorator that caused the beat */
|
||||
el_val_t engram_self_anchor_capture(void);
|
||||
|
||||
Reference in New Issue
Block a user