code wiki / _hdl_build / nx_engineer_crash_test.nx
nx_engineer_crash_test.nx source
↩ module page · 52 lines · 2971 B
1// nx_engineer_crash_test.nx -- the Engineer catches a crash vs a clean exit. Runs a
2// known crasher (null write -> SIGSEGV) and a clean control, and proves it
3// distinguishes a SIGNAL DEATH from a normal exit -- the thing the gate runner's
4// exit-code-only check misses. Build lane provides /tmp/eng_crasher.elf and
5// /tmp/eng_clean.elf. Known answer: crasher = CRASH signal 11, clean = exit 0.
6
7import "nx_engineer_crash.nx"
8
9func ec_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 }
10func ec_num(v: i64) -> i64 {
11 let b: *u8 = sys_mmap(28); var m: i64 = v; if m < 0 { m = 0 - m }
12 let t: *u8 = sys_mmap(28); var k: i64 = 0
13 if m == 0 { t[0] = 48; k = 1 }
14 while m > 0 { t[k] = 48 + (m % 10); m = m / 10; k = k + 1 }
15 var i: i64 = 0; while i < k { b[i] = t[k - 1 - i]; i = i + 1 }
16 sys_write(1, b, k); return 0
17}
18func ec_report(label: *u8, rc: i64) -> i64 {
19 ec_puts(label)
20 if eng_crashed(rc) == 1 { ec_puts(" CRASHED -- signal " as *u8); ec_num(eng_signal(rc)); ec_puts(" = " as *u8); ec_puts(eng_sig_name(eng_signal(rc))); ec_puts("\n" as *u8) }
21 else { ec_puts(" exited code " as *u8); ec_num(rc); ec_puts("\n" as *u8) }
22 return 0
23}
24
25func main() -> i64 {
26 ec_puts("=== Engineer: catches COMPILE failures AND crashes (the full pipeline) ===\n" as *u8)
27
28 // UPSTREAM: a reserved-keyword source must be caught at COMPILE, before it can
29 // become a garbage binary that segfaults (the exact bug we just hit).
30 let kg: *u8 = "_offc/nx_cc_known_good.elf" as *u8
31 let rc_bad: i64 = eng_compile(kg, "runtime/_hdl_build/nx_eng_badsrc.nx" as *u8, "/tmp/eng_bad.s" as *u8)
32 let rc_good: i64 = eng_compile(kg, "runtime/_hdl_build/nx_eng_clean.nx" as *u8, "/tmp/eng_good.s" as *u8)
33 ec_puts(" compile bad-source : " as *u8); if rc_bad < 0 { ec_puts("CAUGHT (compile failed)\n" as *u8) } else { ec_puts("MISSED (compiled?!)\n" as *u8) }
34 ec_puts(" compile good-source: " as *u8); if rc_good == 0 { ec_puts("ok\n" as *u8) } else { ec_puts("false-fail\n" as *u8) }
35
36 // DOWNSTREAM: a SIGSEGV must be caught at run (vs a clean exit).
37 let rc_c: i64 = eng_run("/tmp/eng_crasher.elf" as *u8, "/tmp/eng_crash.out" as *u8)
38 let rc_k: i64 = eng_run("/tmp/eng_clean.elf" as *u8, "/tmp/eng_clean.out" as *u8)
39 ec_report(" run crasher:" as *u8, rc_c)
40 ec_report(" run clean :" as *u8, rc_k)
41
42 // GATE: compile failure caught, good compile ok, crash caught as SIGSEGV, clean ok.
43 if rc_bad >= 0 { sys_exit(1); return 1 }
44 if rc_good != 0 { sys_exit(2); return 2 }
45 if eng_crashed(rc_c) != 1 { sys_exit(3); return 3 }
46 if eng_signal(rc_c) != 11 { sys_exit(4); return 4 }
47 if eng_crashed(rc_k) != 0 { sys_exit(5); return 5 }
48 if rc_k != 0 { sys_exit(6); return 6 }
49 ec_puts(" -> the Engineer guards the whole pipeline: compile-fail + crash, not exit-codes only.\n" as *u8)
50 sys_exit(0)
51 return 0
52}