code wiki / _hdl_build / nx_alias_layout_gate.nx
nx_alias_layout_gate.nx source
↩ module page · 100 lines · 4537 B
1// nx_alias_layout_gate.nx -- MONITOR for the type-alias struct-layout parity class (seq521).
2//
3// THE CLASS: the C anchor (parse.c) resolves `type NAME = BASE` aliases; for a long time the
4// self-hosted parser did not, so a struct field typed with an alias fell through parse_type to the
5// TY_VOID size-0 placeholder. Every field of an aliased type then had size 0, later field offsets
6// collapsed onto each other, a pointer field landed at offset 0 and was overwritten by an int field,
7// and dereferencing that tiny integer segfaulted. It was found bits-up (NxMesh.verts read back as
8// the literal 4) and cost a SIGSEGV in nx_landmark_anatomy.
9//
10// WHY THIS FILE EXISTS: the artifact that proved seq521 -- nx_segfield_repro.nx -- only PRINTS. It
11// has no verdict, so no judge and no build driver can fail on it, and nothing guarded the class
12// afterwards. seq521 and seq715 were the SAME class (self-host parity gaps against the C anchor) and
13// one had been fixed while the other had not; nobody swept for siblings. This turns the probe into a
14// gate that the driver can reach, with the fn-pointer half deliberately left to nx_fnptr_call_gate
15// rather than duplicated here.
16//
17// DISCRIMINATING BY CONSTRUCTION: every tooth reads RAW i64 offsets off the struct base. That is
18// precisely what collapses under the defect, so a regressed compiler cannot make these pass.
19//
20// license_tier: ORIGINAL No hw writes (Rule 26).
21import "nx_syscalls.nx"
22import "nx_gate_verdict.nx"
23
24// Declared here rather than imported so the gate also exercises alias REGISTRATION itself.
25// Order matters: a chained alias resolves because names register in source order.
26type gi = i64
27type gi2 = gi
28
29struct AllA { a: gi, b: gi, c: gi }
30struct AthenP { n: gi, p: *AllA, w: gi }
31struct PthenA { p: *AllA, n: gi, w: gi }
32struct Chain { x: gi2, y: gi2 }
33
34const SBYTES: i64 = 64
35const GUARD_A: i64 = 11
36const GUARD_B: i64 = 22
37const GUARD_C: i64 = 33
38const GUARD_N: i64 = 7
39const CHAIN_X: i64 = 5
40const CHAIN_Y: i64 = 6
41
42func ret_alias() -> gi { return 77 }
43
44func main() -> i64 {
45 let ctr: *i64 = gv_ctr()
46 gv_head("nx_alias_layout_gate -- type-alias struct field layout (seq521 parity monitor)" as *u8)
47
48 // T1: an ALL-ALIAS struct must lay its fields out at 0/8/16. Under the defect every field
49 // collapsed to offset 0 and the last write won at all three slots.
50 let x: *AllA = sys_mmap(SBYTES) as *AllA
51 x.a = GUARD_A
52 x.b = GUARD_B
53 x.c = GUARD_C
54 let rx: *i64 = x as *i64
55 var t1: i64 = 0
56 if rx[0] == GUARD_A { if rx[1] == GUARD_B { if rx[2] == GUARD_C { t1 = 1 } } }
57 gv_check("T1 all-alias struct occupies distinct offsets 0/8/16" as *u8, t1, ctr)
58
59 // T2/T3: alias THEN pointer -- the shape that actually segfaulted. The pointer must not land
60 // on offset 0 and clobber the leading int, and must read back as the address stored.
61 let y: *AthenP = sys_mmap(SBYTES) as *AthenP
62 y.n = GUARD_N
63 y.p = x
64 let ry: *i64 = y as *i64
65 var t2: i64 = 0
66 if ry[0] == GUARD_N { t2 = 1 }
67 gv_check("T2 alias-then-pointer: the pointer does not land at offset 0" as *u8, t2, ctr)
68 var t3: i64 = 0
69 if (y.p as i64) == (x as i64) { t3 = 1 }
70 gv_check("T3 alias-then-pointer: the pointer field reads back the stored address" as *u8, t3, ctr)
71
72 // T4: pointer FIRST survived even under the defect, so it is the NEGATIVE CONTROL -- it proves
73 // the gate is exercising layout rather than trivially passing everything.
74 let z: *PthenA = sys_mmap(SBYTES) as *PthenA
75 z.p = x
76 z.n = 9
77 let rz: *i64 = z as *i64
78 var t4: i64 = 0
79 if rz[0] == (x as i64) { if rz[1] == 9 { t4 = 1 } }
80 gv_check("T4 pointer-first control: layout still correct (was the surviving case)" as *u8, t4, ctr)
81
82 // T5: a CHAINED alias (gi2 -> gi -> i64) must resolve to the concrete size too.
83 let c: *Chain = sys_mmap(SBYTES) as *Chain
84 c.x = CHAIN_X
85 c.y = CHAIN_Y
86 let rc: *i64 = c as *i64
87 var t5: i64 = 0
88 if rc[0] == CHAIN_X { if rc[1] == CHAIN_Y { t5 = 1 } }
89 gv_check("T5 chained alias resolves to the concrete size" as *u8, t5, ctr)
90
91 // T6: an alias as a RETURN type, the non-struct half of the same resolution path.
92 var t6: i64 = 0
93 if ret_alias() == 77 { t6 = 1 }
94 gv_check("T6 alias as a function return type" as *u8, t6, ctr)
95
96 let rc2: i64 = gv_verdict("ALIAS-LAYOUT-GATE" as *u8, ctr,
97 "alias field offsets, chained aliases, pointer-first control" as *u8)
98 sys_exit(rc2)
99 return rc2
100}