nx_addrof_test.nx source
↩ module page · 53 lines · 1950 B
1// nx_addrof_test.nx -- PREVENT/MONITOR pillar for the address-of-local
2// codegen bug class (T#native-addrof).
3//
4// BUG (found 2026-05-28): bare `&x` on an alloca-backed local returned
5// the raw alloca value-id, which the codegen AUTO-LOADS (movq slot) ->
6// the slot CONTENTS were passed as a pointer -> SEGV. Latent in
7// nx_jose's `&off` (never run under the native compiler).
8// FIX: parser emits OP_ADDR_OF -> codegen uses the AS-ADDRESS (leaq)
9// path. THIS test is the regression guard: any reintroduction of the
10// auto-load behavior fails it loudly.
11//
12// Run under the native compiler in the daily smoke.
13
14import "nx_syscalls.nx"
15
16struct AoPair { a: i64, b: i64 }
17
18func ao_bump(p: *i64) -> i64 { p[0] = p[0] + 41; return 0 }
19
20// out-param: callee writes a NEW pointer into the caller's *i64 slot.
21func ao_set_ptr(out: *i64, val: i64) -> i64 {
22 let buf: *i64 = sys_mmap(8) as *i64
23 buf[0] = val
24 out[0] = buf as i64
25 return 0
26}
27
28func main() -> i64 {
29 // 1. &value-local: callee modifies x through the pointer.
30 var x: i64 = 1
31 ao_bump(&x)
32 if x != 42 { sys_write(1, "T1 &value FAIL\n" as *u8, 15); return 1 }
33
34 // 2. &pointer-local (out-param): callee stores a pointer into p's slot.
35 var p: *i64 = 0 as *i64
36 ao_set_ptr((&p) as *i64, 1234)
37 if (p as i64) == 0 { sys_write(1, "T2 &ptr-slot null FAIL\n" as *u8, 23); return 2 }
38 if p[0] != 1234 { sys_write(1, "T2 &ptr-slot value FAIL\n" as *u8, 24); return 3 }
39
40 // 3. &struct.field chain still works (no-regression).
41 let pair: *AoPair = sys_mmap(16) as *AoPair
42 pair.a = 7
43 pair.b = 9
44 let fa: *i64 = &pair.a
45 let fb: *i64 = &pair.b
46 fa[0] = 70
47 fb[0] = 90
48 if pair.a != 70 { sys_write(1, "T3 &field.a FAIL\n" as *u8, 17); return 4 }
49 if pair.b != 90 { sys_write(1, "T3 &field.b FAIL\n" as *u8, 17); return 5 }
50
51 sys_write(1, "ADDR-OF KAT PASS (value + ptr-out-param + field-chain)\n" as *u8, 54)
52 return 0
53}