// Runtime contract for a whole 24B str/slice header loaded // BY VALUE through a pointer (`let s = *h` where h:*str / h:*[]T). C1b (#4): // the N_UN TK_STAR deref arm fell through to a scalar MOVQ (AX),AX that loaded // ONLY word0 (.ptr); .len/.cap were then stored from stale BX/CX, so len(*h) // and cap(*h) read garbage. byte-id proves the two stages agree, NOT that the // emitted code is correct (this gap was byte-id-identical on both stages). // // WHY the decoy: the pre-fix bug leaves .len/.cap in whatever BX/CX happened to // hold. A naive `let backing="abcde"; let s=*h` PASSES even broken, because the // literal's header-load left BX/CX = backing's own len/cap moments earlier — // the exact register coincidence that let this class hide. Each fn interposes a // DIFFERENT-sized decoy header right before the deref, so any stale BX/CX hold // the decoy's len/cap (≠ backing's). Verified: with the fix reverted all four // fns RED, with the fix all GREEN. The s[i] element reads additionally pin .ptr // (loaded into AX) — covering the whole header on str and slice, in both the // let-bind and fn-return shapes that propagate the bug. package deref_hdr_test; fn ret_str_deref(h: *str) str = { return *h; }; fn ret_slice_deref(h: *[]i32) []i32 = { return *h; }; @test fn str_whole_deref() void = { // Whole str loaded by value through *str. The decoy ("xy", len 2) is the // last header materialized before `*h`, so a pre-fix stale BX/CX hold // 2/2, not backing's 5/5 — the .len/.cap asserts then RED on the bug. // The s[i] byte reads stride from .ptr, pinning AX (word0) too. let backing: str = "abcde"; let h: *str = &backing; let decoy: str = "xy"; assert(decoy.len: i32 == 2); let s: str = *h; assert(s.len: i32 == 5); assert(s.cap: i32 == 5); assert(s[0]: i32 == 97); assert(s[1]: i32 == 98); assert(s[4]: i32 == 101); }; @test fn slice_whole_deref() void = { // Whole slice loaded by value through *[]i32 — same 3-word header load. // Decoy (len 1) clobbers the stale-register path away from backing's 3. let backing: []i32 = [10i32, 20i32, 30i32]; let h: *[]i32 = &backing; let decoy: []i32 = [1i32]; assert(decoy.len: i32 == 1); let s: []i32 = *h; assert(s.len: i32 == 3); assert(s.cap: i32 == 3); assert(s[0]: i32 == 10); assert(s[1]: i32 == 20); assert(s[2]: i32 == 30); }; @test fn str_deref_as_return() void = { // `return *h` feeds the same arm into the return registers. The decoy // ("xyz", len 3) before the call seeds BX/CX wrong, so a pre-fix callee // that returns only .ptr surfaces 3/3 here instead of backing's 4/4. let backing: str = "abcd"; let h: *str = &backing; let decoy: str = "xyz"; assert(decoy.len: i32 == 3); let s: str = ret_str_deref(h); assert(s.len: i32 == 4); assert(s.cap: i32 == 4); assert(s[0]: i32 == 97); }; @test fn slice_deref_as_return() void = { let backing: []i32 = [7i32, 8i32]; let h: *[]i32 = &backing; let decoy: []i32 = [1i32, 2i32, 3i32, 4i32]; assert(decoy.len: i32 == 4); let s: []i32 = ret_slice_deref(h); assert(s.len: i32 == 2); assert(s.cap: i32 == 2); assert(s[1]: i32 == 8); };