nx_compiler_bounds_cli_gate.nx source
↩ module page · 154 lines · 11805 B
1// End-to-end CLI qualification of the staged compiler against a supplied incumbent.
2// Uses existing timed capture, per-run exclusive fixtures and complete artifact byte comparisons.
3import "nx_wat_refuse_gate.nx"
4import "nx_gate_verdict.nx"
5const BC_PAGE: i64=65536
6const BC_PRIVATE: i64=448
7const BC_I64_MAX: i64=9223372036854775807
8static bc_timeout: i64
9static bc_case_id: i64
10static bc_output: *u8
11static bc_output_n: i64
12func bc_number(s: *u8) -> i64 {
13 var n: i64=0;var i: i64=0
14 while s[i]!=(0 as u8) {let d: i64=s[i] as i64-48;if d<0 || d>9{return 0-1};if n>(BC_I64_MAX-d)/10{return 0-1};n=n*10+d;i=i+1}
15 if i==0 || n==0{return 0-1};return n
16}
17func bc_read(path: *u8,out: *u8) -> i64 {
18 let fd: i64=sys_openat_rd(path);if fd<0{return 0-1}
19 var n: i64=0;var eof: i64=0
20 while n<WR_CAP-1 {let got: i64=sys_read(fd,((out as i64)+n) as *u8,WR_CAP-1-n);if got==0{eof=1;break};if got<0{break};n=n+got}
21 let closed: i64=sys_close(fd);if eof!=1 || closed!=0{return 0-1};out[n]=0 as u8;return n
22}
23func bc_equal(a: *u8,an: i64,b: *u8,bn: i64) -> i64 {
24 if an<1 || an!=bn{return 0};var i: i64=0
25 while i<an{if a[i]!=b[i]{return 0};i=i+1};return 1
26}
27// All invocations use the SAME input path; fresh numbered outputs avoid stale-success evidence.
28func bc_run(subject: *u8,dir: *u8,source: *u8,options: *i64,noptions: i64,want: i64,cause: *u8,label: *u8,c: *i64) -> i64 {
29 gv_puts("case=" as *u8);gv_puts(label);gv_puts("\n" as *u8)
30 bc_output_n=0;bc_case_id=bc_case_id+1
31 let input: *u8=sys_mmap(WR_PATH);let output: *u8=sys_mmap(WR_PATH)
32 let avbytes: i64=(noptions+4)*WR_SPAN
33 let av: *i64=sys_mmap(avbytes) as *i64;let log: *u8=sys_mmap(WR_CAP)
34 let count: *i64=sys_mmap(WR_SPAN) as *i64;let truncated: *i64=sys_mmap(WR_SPAN) as *i64
35 if (input as i64)<=0 || (output as i64)<=0 || (av as i64)<=0 || (log as i64)<=0 || (count as i64)<=0 || (truncated as i64)<=0 {gv_check("case buffers allocated" as *u8,0,c);return 0}
36 gk_join(input,dir,"subject.nx" as *u8)
37 var p: i64=gk_cat(output,0,dir);p=gk_cat(output,p,"/output-" as *u8);p=gk_catn(output,p,bc_case_id);p=gk_cat(output,p,".wat" as *u8);output[p]=0 as u8
38 let written: i64=gk_write(input,source)
39 gv_check("entire fixture written" as *u8,written==gk_len(source),c)
40 if written!=gk_len(source){return 0}
41 av[0]=subject as i64;av[1]=input as i64;av[2]=output as i64
42 var k: i64=0;while k<noptions{av[3+k]=options[k];k=k+1};av[3+noptions]=0
43 let rc: i64=tr_run_capture_tr(subject,av,log,WR_CAP-1,count,bc_timeout,truncated)
44 if count[0]>=0 && count[0]<WR_CAP{log[count[0]]=0 as u8}
45 gv_check("compiler capture completed without truncation" as *u8,count[0]>=0 && count[0]<WR_CAP-1 && truncated[0]==0,c)
46 gv_check("compiler exit matches exact expected status" as *u8,rc==want,c)
47 if want==0 {
48 bc_output_n=bc_read(output,bc_output)
49 gv_check("artifact read fully to EOF" as *u8,bc_output_n>0,c)
50 gv_check("successful artifact contains module" as *u8,bc_output_n>0 && gk_has(bc_output,"(module\n" as *u8)==1,c)
51 if gk_len(cause)>0{gv_check("successful artifact contains required layout witness" as *u8,bc_output_n>0 && gk_has(bc_output,cause)==1,c)}
52 }else{
53 gv_check("refusal names expected cause" as *u8,count[0]>0 && gk_has(log,cause)==1,c)
54 gv_check("refusal creates no artifact" as *u8,gk_exists(output)==0,c)
55 }
56 gv_values_head();gv_kv("case_index" as *u8,bc_case_id);gv_kv("compiler_exit" as *u8,rc);gv_kv("artifact_bytes" as *u8,bc_output_n)
57 sys_munmap(input,WR_PATH);sys_munmap(output,WR_PATH);sys_munmap(av as *u8,avbytes);sys_munmap(log,WR_CAP);sys_munmap(count as *u8,WR_SPAN);sys_munmap(truncated as *u8,WR_SPAN)
58 return rc==want
59}
60func bc_save(dst: *u8) -> i64 {var i: i64=0;while i<bc_output_n{dst[i]=bc_output[i];i=i+1};return bc_output_n}
61func bc_literal(characters: i64) -> *u8 {
62 let prefix: *u8="func main() -> *u8 { return \"" as *u8
63 let suffix: *u8="\" }\n" as *u8
64 let n: i64=gk_len(prefix)+characters+gk_len(suffix)+1
65 let out: *u8=sys_mmap(n);if (out as i64)<=0{return 0 as *u8}
66 var p: i64=gk_cat(out,0,prefix);var k: i64=0
67 while k<characters{out[p]=97 as u8;p=p+1;k=k+1}
68 p=gk_cat(out,p,suffix);out[p]=0 as u8;return out
69}
70func main(argc: i64,argv: **u8) -> i64 {
71 if argc!=5{gv_puts("usage: compiler-bounds-cli-gate <incumbent> <staged> /tmp/fresh-root timeout-ms\n" as *u8);return 3}
72 let old: *u8=argv[1] as *u8;let subject: *u8=argv[2] as *u8;let dir: *u8=argv[3] as *u8
73 bc_timeout=bc_number(argv[4] as *u8);if bc_timeout<1{return 3}
74 let dn: i64=gk_len(dir);if dn<=5 || dn>=WR_PATH/2{return 3}
75 if dir[0]!=(47 as u8)||dir[1]!=(116 as u8)||dir[2]!=(109 as u8)||dir[3]!=(112 as u8)||dir[4]!=(47 as u8)||dir[5]==(46 as u8){return 3}
76 var i: i64=5;while i<dn{if dir[i]==(47 as u8)||dir[i]<=(32 as u8){return 3};i=i+1}
77 let c: *i64=gv_ctr();gv_head("COMPILER-BOUNDS-CLI / actual staged and incumbent binaries" as *u8)
78 gv_need("incumbent compiler present" as *u8,gk_exists(old),c);gv_need("staged compiler present" as *u8,gk_exists(subject),c)
79 let made: i64=sys_mkdir(dir,BC_PRIVATE);gv_check("exclusive private fixture root" as *u8,made==0,c)
80 if made!=0{return gv_verdict("COMPILER-BOUNDS-CLI" as *u8,c,"fixture isolation refused" as *u8)}
81 bc_output=sys_mmap(WR_CAP);let saved: *u8=sys_mmap(WR_CAP);let opts: *i64=sys_mmap(WR_SPAN*8) as *i64
82 if (bc_output as i64)<=0||(saved as i64)<=0||(opts as i64)<=0{gv_check("gate buffers allocated" as *u8,0,c);return gv_verdict("COMPILER-BOUNDS-CLI" as *u8,c,"allocation failed" as *u8)}
83 // Bind pointer literals before indexed stores: current native analyzer requires this form.
84 let arena_option: *u8="--arena-pages" as *u8
85 let limit_option: *u8="--static-limit-pages" as *u8
86 let shared_option: *u8="--shared" as *u8
87 let pages_one: *u8="1" as *u8
88 let pages_two: *u8="2" as *u8
89 let pages_three: *u8="3" as *u8
90 let pages_four: *u8="4" as *u8
91 let source_value: *u8="source" as *u8
92 let bad_suffix: *u8="1x" as *u8
93 let bad_plus: *u8="+1" as *u8
94 let bad_negative: *u8="-1" as *u8
95 let bad_zero: *u8="0" as *u8
96 let bad_range: *u8="65537" as *u8
97 let bad_overflow: *u8="9223372036854775808" as *u8
98 let bad_empty: *u8="" as *u8
99 let tiny: *u8="func main() -> *u8 { return \"abc\" }\n" as *u8
100 bc_run(old,dir,tiny,opts,0,0,"" as *u8,"incumbent no flags" as *u8,c);let oldn: i64=bc_save(saved)
101 bc_run(subject,dir,tiny,opts,0,0,"" as *u8,"staged no flags" as *u8,c)
102 gv_check("no-flags complete output byte parity" as *u8,bc_equal(saved,oldn,bc_output,bc_output_n),c)
103 opts[0]=arena_option as i64;opts[1]=pages_one as i64;opts[2]=limit_option as i64;opts[3]=pages_two as i64
104 bc_run(subject,dir,tiny,opts,4,0,"(data (i32.const 65536)" as *u8,"plain arena then limit" as *u8,c);let plainn: i64=bc_save(saved)
105 opts[0]=limit_option as i64;opts[1]=pages_two as i64;opts[2]=arena_option as i64;opts[3]=pages_one as i64
106 bc_run(subject,dir,tiny,opts,4,0,"(data (i32.const 65536)" as *u8,"plain limit then arena" as *u8,c)
107 gv_check("plain option ordering preserves all emitted bytes" as *u8,bc_equal(saved,plainn,bc_output,bc_output_n),c)
108 opts[4]=shared_option as i64;opts[5]=pages_three as i64;opts[6]=pages_four as i64
109 bc_run(subject,dir,tiny,opts,7,0,"(memory 3 4 shared)" as *u8,"shared limit then arena" as *u8,c);let sharedn: i64=bc_save(saved)
110 opts[0]=arena_option as i64;opts[1]=pages_one as i64;opts[2]=limit_option as i64;opts[3]=pages_two as i64
111 bc_run(subject,dir,tiny,opts,7,0,"(memory 3 4 shared)" as *u8,"shared arena then limit" as *u8,c)
112 gv_check("shared option ordering preserves all emitted bytes" as *u8,bc_equal(saved,sharedn,bc_output,bc_output_n),c)
113 opts[0]=shared_option as i64;opts[1]=pages_three as i64;opts[2]=pages_four as i64
114 opts[3]=arena_option as i64;opts[4]=pages_one as i64;opts[5]=limit_option as i64;opts[6]=pages_two as i64
115 bc_run(subject,dir,tiny,opts,7,0,"(memory 3 4 shared)" as *u8,"numeric shared first then bounds" as *u8,c)
116 gv_check("shared-first numeric ordering preserves all emitted bytes" as *u8,bc_equal(saved,sharedn,bc_output,bc_output_n),c)
117 let source_pages: *u8="static nx_wasm_pages_req: i64 = 3\nfunc main() -> *u8 { return \"abc\" }\n" as *u8
118 opts[1]=source_value as i64
119 bc_run(subject,dir,source_pages,opts,7,0,"(memory 3 4 shared)" as *u8,"source-derived shared first then bounds" as *u8,c);let sourcen: i64=bc_save(saved)
120 opts[0]=arena_option as i64;opts[1]=pages_one as i64;opts[2]=limit_option as i64;opts[3]=pages_two as i64
121 opts[4]=shared_option as i64;opts[5]=source_value as i64;opts[6]=pages_four as i64
122 bc_run(subject,dir,source_pages,opts,7,0,"(memory 3 4 shared)" as *u8,"bounds first then source-derived shared" as *u8,c)
123 gv_check("source-derived shared ordering preserves all emitted bytes" as *u8,bc_equal(saved,sourcen,bc_output,bc_output_n),c)
124 let bad: *i64=sys_mmap(WR_SPAN*7) as *i64
125 if (bad as i64)<=0{gv_check("invalid-value table allocated" as *u8,0,c);return gv_verdict("COMPILER-BOUNDS-CLI" as *u8,c,"allocation failed" as *u8)}
126 bad[0]=bad_suffix as i64;bad[1]=bad_plus as i64;bad[2]=bad_negative as i64;bad[3]=bad_zero as i64;bad[4]=bad_range as i64;bad[5]=bad_overflow as i64;bad[6]=bad_empty as i64
127 var flag: i64=0
128 while flag<2{
129 opts[0]=arena_option as i64;if flag==1{opts[0]=limit_option as i64}
130 var k: i64=0
131 while k<7{
132 opts[1]=bad[k];gv_puts("flag=" as *u8);gv_puts(opts[0] as *u8);gv_puts(" value=" as *u8);gv_puts(opts[1] as *u8);gv_puts("\n" as *u8)
133 bc_run(subject,dir,tiny,opts,2,11,"must be complete positive decimal integers within wasm32" as *u8,"malformed page value" as *u8,c);k=k+1
134 }
135 bc_run(subject,dir,tiny,opts,1,11,"requires one positive decimal page count" as *u8,"missing page value" as *u8,c);flag=flag+1
136 }
137 opts[0]=arena_option as i64;opts[1]=pages_two as i64;opts[2]=limit_option as i64;opts[3]=pages_one as i64
138 let extent_cause: *u8="static layout exceeds supplied limit or limit is below arena base" as *u8
139 bc_run(subject,dir,tiny,opts,4,65,extent_cause,"limit below arena" as *u8,c)
140 opts[1]=pages_one as i64
141 bc_run(subject,dir,tiny,opts,4,65,extent_cause,"nonempty static data beyond zero-width reservation" as *u8,c)
142 opts[3]=pages_two as i64
143 let exact_plain: *u8=bc_literal(BC_PAGE-1);let over_plain: *u8=bc_literal(BC_PAGE)
144 let exact_shared: *u8=bc_literal(BC_PAGE-1-WR_SPAN);let over_shared: *u8=bc_literal(BC_PAGE-WR_SPAN)
145 if (exact_plain as i64)<=0||(over_plain as i64)<=0||(exact_shared as i64)<=0||(over_shared as i64)<=0{gv_check("exact-reservation fixtures allocated" as *u8,0,c);return gv_verdict("COMPILER-BOUNDS-CLI" as *u8,c,"allocation failed" as *u8)}
146 bc_run(subject,dir,exact_plain,opts,4,0,"(data (i32.const 65536)" as *u8,"plain exact page including string terminator" as *u8,c)
147 bc_run(subject,dir,over_plain,opts,4,65,extent_cause,"plain one byte over reservation" as *u8,c)
148 opts[4]=shared_option as i64;opts[5]=pages_three as i64;opts[6]=pages_four as i64
149 bc_run(subject,dir,exact_shared,opts,7,0,"(memory 3 4 shared)" as *u8,"shared exact page including aligned initialization cell" as *u8,c)
150 bc_run(subject,dir,over_shared,opts,7,65,extent_cause,"shared payload one byte over exact reservation" as *u8,c)
151 gv_values_head();gv_kv("subject_invocations" as *u8,bc_case_id)
152 gv_puts("retained_fixture=" as *u8);gv_puts(dir);gv_puts("\n" as *u8)
153 return gv_verdict("COMPILER-BOUNDS-CLI" as *u8,c,"actual CLI plain/shared order parity; strict syntax exit11; bounds exit65; exact reservations and incumbent no-flags parity; native fixture qualification only" as *u8)
154}