_derefcast_minrepro.nx source
↩ module page · 47 lines · 1563 B
1// _derefcast_minrepro.nx -- min repro: deref + pointer-cast in ONE
2// expression (`*p as *u8`) miscompiles on the native x86 lane.
3//
4// Found 2026-06-10 building nx_tls13_ch_compat_test (B2 row): a
5// pointer value stored through an out-param read back via
6// let host: *u8 = *host_p as *u8
7// then dereferenced -> SIGSEGV. Flattening into
8// let hv: i64 = host_p[0]
9// let host: *u8 = hv as *u8
10// compiles correctly. Same family as the 4-deep nested-if and
11// >6-arg tail-call landmines: expression-shape miscompile.
12//
13// exit 0 = BOTH shapes work (defect fixed -- browser-gate row).
14// exit 1/2 = a shape produced a wrong value; SIGSEGV = the original
15// defect (pre-fix compilers byte-load the cell and deref garbage).
16//
17// FIXED 2026-06-10: parse_unary wrapper owns the trailing `as` so
18// prefix `*` binds tighter than `as` (see nx_parse.nx). This row
19// guards the lane against precedence regressions, like _arg7_minrepro
20// guards the >6-arg tail-call drop.
21//
22// expect_exit: 0
23// license_tier: ORIGINAL
24
25import "nx_syscalls.nx"
26
27func main() -> i64 {
28 let buf: *u8 = sys_mmap(64)
29 buf[0] = 42 as u8
30
31 // Stash the pointer in an i64 cell (the out-param pattern).
32 let cell: *i64 = sys_mmap(16) as *i64
33 cell[0] = buf as i64
34
35 // Flattened shape (known-good).
36 let hv: i64 = cell[0]
37 let p1: *u8 = hv as *u8
38 let v1: i64 = p1[0] & 0xff
39
40 // One-expression shape (the suspect).
41 let p2: *u8 = *cell as *u8
42 let v2: i64 = p2[0] & 0xff
43
44 if v1 != 42 { return 1 }
45 if v2 != 42 { return 2 }
46 return 0
47}