code wiki / _hdl_build / _regalloc_lf_repro.nx
_regalloc_lf_repro.nx source
↩ module page · 54 lines · 2969 B
1// _regalloc_lf_repro.nx -- candidate TEN-SECOND repro for LM-REGALLOC: the
2// large-frame / high-register-pressure miscompile where the x86 regalloc
3// miscalculates an alloca-slot offset so a local write lands on a POINTER
4// ARG's spill slot, corrupting it (the parse_stmt in-source comment; the
5// same bug my && short-circuit change surfaced by enlarging the function).
6// RECIPE: pointer arg `p` read early + many if-expr ALLOCAS + CALLS (force p
7// to spill) + p re-read/written AFTER the allocas. If the bug fires, p is
8// corrupted -> p[1]=v1 segfaults or p[1]!=42. GREEN(exit0)=no bug here;
9// RED(segfault/!=42)=repro = the team's deterministic gate. license_tier: ORIGINAL
10import "nx_syscalls.nx"
11func rp(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
12func rn(v: i64) -> i64 { let b: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1}; while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1}; var i: i64=0; while i<k{b[i]=t[k-1-i];i=i+1}; sys_write(1,b,k); return 0 }
13// a real call so the regalloc must SPILL the pointer arg across it
14func work(x: i64) -> i64 { return x * 2 + 1 }
15// the victim: pointer arg + if-expr allocas + calls + re-read of p
16func bug(p: *i64) -> i64 {
17 let v0: i64 = p[0]
18 let a: i64 = work(v0)
19 let b: i64 = if a == 0 then work(1) else work(2)
20 let c: i64 = work(a + b)
21 let d: i64 = if b == 3 then work(3) else work(4)
22 let e: i64 = work(c + d)
23 let f: i64 = if c == 5 then work(5) else work(6)
24 let g: i64 = work(e + f)
25 let h: i64 = if d == 7 then work(7) else work(8)
26 let i2: i64 = work(g + h)
27 let j: i64 = if e == 9 then work(9) else work(10)
28 let k2: i64 = work(i2 + j)
29 let l: i64 = if f == 11 then work(11) else work(12)
30 let m2: i64 = work(k2 + l)
31 let n2: i64 = if g == 13 then work(13) else work(14)
32 let o: i64 = work(m2 + n2)
33 let q: i64 = if h == 15 then work(15) else work(16)
34 let r2: i64 = work(o + q)
35 let s2: i64 = if i2 == 17 then work(17) else work(18)
36 let acc: i64 = a + b + c + d + e + f + g + h + i2 + j + k2 + l + m2 + n2 + o + q + r2 + s2
37 // re-read the pointer AFTER all the allocas; if regalloc corrupted p's
38 // spill slot, this read/write goes wrong (the bug)
39 let v1: i64 = p[0]
40 p[1] = v1
41 return acc
42}
43func main() -> i64 {
44 rp("=== LM-REGALLOC large-frame repro: pointer-arg corruption under alloca pressure ===\n" as *u8)
45 let p: *i64 = sys_mmap(64) as *i64
46 p[0] = 42
47 p[1] = 0
48 let acc: i64 = bug(p)
49 rp(" acc=" as *u8); rn(acc); rp(" p[0]=" as *u8); rn(p[0]); rp(" p[1]=(re-read of p[0])=" as *u8); rn(p[1]); rp("\n" as *u8)
50 if p[1] == 42 { rp(" REGALLOC-REPRO: GREEN -- pointer arg INTACT (bug did NOT fire in this shape)\n" as *u8); sys_exit(0); return 0 }
51 rp(" REGALLOC-REPRO: RED -- pointer arg CORRUPTED (p[1] != 42) = LM-REGALLOC reproduced\n" as *u8)
52 sys_exit(1)
53 return 1
54}