nx_nxa_morf_malformed_gate.nx source
↩ module page · 264 lines · 13334 B
1// nx_nxa_morf_malformed_gate.nx -- drive the promoted evaluator with checksum-valid
2// shape/arithmetic counterexamples. Every refusal must preserve an existing output.
3// Test fixture dimensions and values are data, not production policy.
4// license_tier: ORIGINAL; no hardware writes; expect_exit: 0
5import "nx_syscalls.nx"
6import "nx_gate_verdict.nx"
7import "nx_gatekit_lib.nx"
8import "nx_nxa.nx"
9import "nx_estate_path.nx"
10
11const MB_ELF: *u8 = "./nx_nxa_morf.elf"
12const MB_DIR: *u8 = "/tmp/nxmorfmalformed"
13const MB_IN: *u8 = "/tmp/nxmorfmalformed/input.nxa"
14const MB_OUT: *u8 = "/tmp/nxmorfmalformed/output.nxa"
15const MB_SENTINEL: *u8 = "NXA-OUTPUT-KEEP\n"
16const MB_WORD: i64 = 8
17const MB_HEAD: i64 = 4
18const MB_ENTRY: i64 = 4
19const MB_SECTIONS: i64 = 3
20const MB_AXES: i64 = 3
21const MB_VERTICES: i64 = 3
22const MB_FACES: i64 = 2
23const MB_FACE_HEAD: i64 = 4
24const MB_MORF_HEAD: i64 = 4
25const MB_CHANNEL_REC: i64 = 2
26const MB_UNIT: i64 = 1000
27const MB_VWORDS: i64 = 1 + MB_VERTICES*MB_AXES
28const MB_FWORDS: i64 = MB_FACE_HEAD + MB_FACES
29const MB_MWORDS: i64 = MB_MORF_HEAD + MB_CHANNEL_REC + MB_FACES*MB_AXES
30const MB_V: i64 = MB_HEAD + MB_SECTIONS*MB_ENTRY
31const MB_F: i64 = MB_V + MB_VWORDS
32const MB_M: i64 = MB_F + MB_FWORDS
33const MB_D: i64 = MB_M + MB_MORF_HEAD + MB_CHANNEL_REC
34const MB_WORDS: i64 = MB_M + MB_MWORDS
35const MB_BYTES: i64 = MB_WORDS*MB_WORD
36const MB_USAGE: i64 = 2
37const MB_BAD: i64 = 3
38const MB_MAX: i64 = 9223372036854775807
39
40// Optional arguments: <subject ELF> <fresh /tmp basename>.
41// Relative ELF paths resolve from ep_anchor's estate root. Omitted args retain
42// the original subject and paths. A supplied basename must create a fresh dir.
43struct MbRun {
44 subject: *u8
45 input: *u8
46 output: *u8
47}
48func mb_pathlen(p: *u8) -> i64 {
49 var n: i64 = 0
50 while p[n] != (0 as u8) { n = n+1 }
51 return n
52}
53func mb_join(a: *u8,b: *u8) -> *u8 {
54 let out: *u8 = sys_mmap(mb_pathlen(a)+mb_pathlen(b)+1)
55 if (out as i64) <= 0 { return 0 as *u8 }
56 var n: i64 = gk_cat(out,0,a)
57 n = gk_cat(out,n,b); out[n] = 0 as u8
58 return out
59}
60func mb_basename(p: *u8) -> i64 {
61 var i: i64 = 0
62 while p[i] != (0 as u8) {
63 let c: i64 = p[i] as i64; var ok: i64 = 0
64 if c >= 48 { if c <= 57 { ok = 1 } }
65 if c >= 65 { if c <= 90 { ok = 1 } }
66 if c >= 97 { if c <= 122 { ok = 1 } }
67 if c == 45 { ok = 1 }; if c == 95 { ok = 1 }
68 if ok == 0 { return 0 }; i = i+1
69 }
70 if i == 0 { return 0 }
71 return 1
72}
73
74func mb_len(s: *u8) -> i64 {
75 var n: i64 = 0
76 while s[n] != (0 as u8) { n = n + 1 }
77 return n
78}
79func mb_write(path: *u8, b: *u8, n: i64) -> i64 {
80 let fd: i64 = sys_openat_wr(path, 420)
81 if fd < 0 { return 0 }
82 let wrote: i64 = sys_write(fd, b, n)
83 sys_close(fd)
84 if wrote != n { return 0 }
85 return 1
86}
87func mb_same(path: *u8, want: *u8, n: i64) -> i64 {
88 let lp: *i64 = sys_mmap(MB_WORD*2) as *i64
89 let b: *u8 = sys_read_file(path, lp)
90 if (b as i64) == 0 { return 0 }
91 if lp[0] != n { sys_free_file(b, lp[0]); return 0 }
92 var i: i64 = 0
93 while i < n {
94 if b[i] != want[i] { sys_free_file(b, lp[0]); return 0 }
95 i = i + 1
96 }
97 sys_free_file(b, lp[0])
98 return 1
99}
100func mb_recheck(h: *i64) -> i64 {
101 var s: i64 = 0
102 while s < MB_SECTIONS {
103 let e: i64 = MB_HEAD + s*MB_ENTRY
104 let payload: *i64 = ((h as i64) + h[e+1]) as *i64
105 h[e+3] = nxa_check2(1, payload, h[e+2])
106 s = s + 1
107 }
108 h[3] = nxa_check2(1, ((h as i64) + MB_HEAD*MB_WORD) as *i64, MB_SECTIONS*MB_ENTRY)
109 return 0
110}
111func mb_fixture() -> *i64 {
112 let h: *i64 = sys_mmap(MB_BYTES) as *i64
113 var i: i64 = 0
114 while i < MB_WORDS { h[i] = 0; i = i + 1 }
115 h[0] = nxa_magic(); h[1] = NXA_VER; h[2] = MB_SECTIONS
116 h[4] = nxa_tag4("VERT" as *u8); h[5] = MB_V*MB_WORD; h[6] = MB_VWORDS
117 h[8] = nxa_tag4("FACE" as *u8); h[9] = MB_F*MB_WORD; h[10] = MB_FWORDS
118 h[12] = nxa_tag4("MORF" as *u8); h[13] = MB_M*MB_WORD; h[14] = MB_MWORDS
119 h[MB_V] = MB_VERTICES
120 // Vertex 1 is deliberately outside FACE; full-file expected output detects global edits.
121 h[MB_V+1] = 10; h[MB_V+2] = 20; h[MB_V+3] = 30
122 h[MB_V+4] = 40; h[MB_V+5] = 50; h[MB_V+6] = 60
123 h[MB_V+7] = 70; h[MB_V+8] = 80; h[MB_V+9] = 90
124 h[MB_F] = MB_FACES; h[MB_F+1] = 2; h[MB_F+2] = 0; h[MB_F+3] = MB_UNIT
125 h[MB_F+4] = 0; h[MB_F+5] = 2
126 h[MB_M] = 1; h[MB_M+1] = MB_FACES; h[MB_M+2] = MB_AXES; h[MB_M+3] = MB_UNIT
127 h[MB_M+4] = nxa_tag4("TEST" as *u8); h[MB_M+5] = MB_FACES
128 h[MB_D] = 3; h[MB_D+1] = 0-4; h[MB_D+2] = 5
129 h[MB_D+3] = 0-6; h[MB_D+4] = 7; h[MB_D+5] = 0-8
130 mb_recheck(h)
131 return h
132}
133func mb_positive(label: *u8, spec: *u8, h: *i64, want: *i64, ctr: *i64,run: *MbRun) -> i64 {
134 if mb_write(run.input, h as *u8, MB_BYTES) == 0 { gv_check(label, 0, ctr); return 0 }
135 if mb_write(run.output, MB_SENTINEL, mb_len(MB_SENTINEL)) == 0 { gv_check(label, 0, ctr); return 0 }
136 let log: *u8 = sys_mmap(GK_BUF)
137 let lp: *i64 = sys_mmap(MB_WORD*2) as *i64
138 let rc: i64 = gk_run_capture(run.subject, "eval" as *u8, run.input, run.output, spec, log, GK_BUF, lp)
139 var ok: i64 = 0
140 if rc == 0 { ok = mb_same(run.output, want as *u8, MB_BYTES) }
141 gv_check(label, ok, ctr)
142 return ok
143}
144func mb_refuse_code(label: *u8, h: *i64, size: i64, spec: *u8, expected_rc: i64, ctr: *i64,run: *MbRun) -> i64 {
145 if mb_write(run.input, h as *u8, size) == 0 { gv_check(label, 0, ctr); return 0 }
146 if mb_write(run.output, MB_SENTINEL, mb_len(MB_SENTINEL)) == 0 { gv_check(label, 0, ctr); return 0 }
147 let log: *u8 = sys_mmap(GK_BUF)
148 let lp: *i64 = sys_mmap(MB_WORD*2) as *i64
149 let rc: i64 = gk_run_capture(run.subject, "eval" as *u8, run.input, run.output, spec, log, GK_BUF, lp)
150 // Exact failure code plus named diagnostic exclude crashes or missing executable as proof.
151 var refused: i64 = 0
152 if rc == expected_rc { refused = gk_out_has(log, lp[0], "MORF-REFUSE" as *u8) }
153 let preserved: i64 = mb_same(run.output, MB_SENTINEL, mb_len(MB_SENTINEL))
154 gv_puts(" rc=" as *u8); gv_num(rc); gv_puts(" preserved=" as *u8); gv_num(preserved); gv_puts("\n" as *u8)
155 var ok: i64 = 0
156 if refused == 1 { if preserved == 1 { ok = 1 } }
157 gv_check(label, ok, ctr)
158 return ok
159}
160func mb_refuse(label: *u8, h: *i64, size: i64, spec: *u8, ctr: *i64,run: *MbRun) -> i64 {
161 return mb_refuse_code(label, h, size, spec, MB_BAD, ctr,run)
162}
163func main(argc: i64, argv: *i64) -> i64 {
164 if ep_anchor() < 0 { gv_puts("MORF-GATE-REFUSE estate anchor unavailable\n" as *u8); return 3 }
165 if argc > 3 { gv_puts("usage: gate [subject-ELF [fresh-tmp-basename]]\n" as *u8); return 2 }
166 var subject: *u8 = MB_ELF
167 var dir: *u8 = MB_DIR
168 let run: *MbRun = sys_mmap(__size_of(MbRun)) as *MbRun
169 if (run as i64) <= 0 { return 3 }
170 run.input = MB_IN; run.output = MB_OUT
171 if argc > 1 { subject = argv[1] as *u8 }
172 if mb_pathlen(subject) == 0 { return 2 }
173 if argc > 2 {
174 let name: *u8 = argv[2] as *u8
175 if mb_basename(name) == 0 { gv_puts("MORF-GATE-REFUSE invalid tmp basename\n" as *u8); return 2 }
176 dir = mb_join("/tmp/" as *u8,name)
177 if (dir as i64) <= 0 { return 3 }
178 if sys_mkdir(dir,493) != 0 { gv_puts("MORF-GATE-REFUSE tmp directory is not fresh\n" as *u8); return 3 }
179 run.input = mb_join(dir,"/input.nxa" as *u8); run.output = mb_join(dir,"/output.nxa" as *u8)
180 if (run.input as i64) <= 0 { return 3 }; if (run.output as i64) <= 0 { return 3 }
181 } else { sys_mkdir(dir,493) }
182 gv_puts("subject=" as *u8); gv_puts(subject); gv_puts(" tmp=" as *u8); gv_puts(dir); gv_puts("\n" as *u8)
183 run.subject = subject
184 let ctr: *i64 = gv_ctr()
185 gv_head("MORF evaluator malformed-input gate: exact transforms and refusal preserves destination" as *u8)
186 let exists: i64 = gk_exists(subject)
187 gv_check("evaluator-present" as *u8, exists, ctr)
188 if exists == 0 { return gv_verdict("NX-MORF-MALFORMED" as *u8, ctr, "evaluator unavailable" as *u8) }
189
190 let zero: *i64 = mb_fixture()
191 mb_positive("zero-weight-byte-identical" as *u8, "0:0" as *u8, mb_fixture(), zero, ctr,run)
192 let full: *i64 = mb_fixture()
193 full[MB_V+1] = 13; full[MB_V+2] = 16; full[MB_V+3] = 35
194 full[MB_V+7] = 64; full[MB_V+8] = 87; full[MB_V+9] = 82
195 mb_recheck(full)
196 mb_positive("full-weight-exact-coordinates-checksums-and-untouched-nonface" as *u8, "0:1000" as *u8, mb_fixture(), full, ctr,run)
197 let neg: *i64 = mb_fixture()
198 neg[MB_V+1] = 7; neg[MB_V+2] = 24; neg[MB_V+3] = 25
199 neg[MB_V+7] = 76; neg[MB_V+8] = 73; neg[MB_V+9] = 98
200 mb_recheck(neg)
201 mb_positive("negative-weight-exact-coordinates-checksums-and-untouched-nonface" as *u8, "0:-1000" as *u8, mb_fixture(), neg, ctr,run)
202
203 var b: *i64 = mb_fixture()
204 b[0] = 0
205 mb_refuse("bad-magic-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
206 b = mb_fixture(); b[1] = 0
207 mb_refuse("invalid-version-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
208 b = mb_fixture(); b[3] = b[3] + 1
209 mb_refuse("bad-table-checksum-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
210 b = mb_fixture(); b[MB_D] = b[MB_D] + 1
211 mb_refuse("bad-payload-checksum-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
212 b = mb_fixture()
213 mb_refuse("short-header-preserves-output" as *u8, b, MB_HEAD*MB_WORD-1, "0:1000" as *u8, ctr,run)
214 mb_refuse("short-payload-preserves-output" as *u8, b, MB_BYTES-1, "0:1000" as *u8, ctr,run)
215 b = mb_fixture(); b[2] = MB_MAX
216 mb_refuse("oversized-section-count-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
217
218 b = mb_fixture(); b[MB_V] = MB_VERTICES-1; mb_recheck(b)
219 mb_refuse("wrong-vert-count-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
220 b = mb_fixture(); b[MB_M+2] = MB_AXES-1; mb_recheck(b)
221 mb_refuse("wrong-morf-stride-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
222 b = mb_fixture(); b[MB_M+1] = MB_FACES-1; mb_recheck(b)
223 mb_refuse("wrong-morf-row-count-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
224 b = mb_fixture(); b[MB_F] = MB_FACES-1; mb_recheck(b)
225 mb_refuse("wrong-face-count-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
226 b = mb_fixture(); b[14] = MB_MORF_HEAD-1; mb_recheck(b)
227 mb_refuse("short-morf-section-header-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
228 b = mb_fixture(); b[MB_M] = 2; mb_recheck(b)
229 mb_refuse("wrong-channel-shape-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
230 b = mb_fixture(); b[MB_M+3] = 0; mb_recheck(b)
231 mb_refuse("zero-weight-unit-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
232 b = mb_fixture(); b[MB_M+5] = MB_FACES+1; mb_recheck(b)
233 mb_refuse("oversized-support-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
234 b = mb_fixture(); b[MB_F+4] = MB_VERTICES; mb_recheck(b)
235 mb_refuse("oob-face-id-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
236 b = mb_fixture(); b[MB_F+4] = 0-1; mb_recheck(b)
237 mb_refuse("negative-face-id-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
238 b = mb_fixture(); b[MB_F+5] = b[MB_F+4]; mb_recheck(b)
239 mb_refuse("duplicate-face-id-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
240
241 b = mb_fixture(); b[MB_D] = MB_MAX; mb_recheck(b)
242 mb_refuse("positive-product-overflow-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
243 b = mb_fixture(); b[MB_D] = 0-MB_MAX-1; mb_recheck(b)
244 mb_refuse("min-times-negative-one-overflow-preserves-output" as *u8, b, MB_BYTES, "0:-1" as *u8, ctr,run)
245 b = mb_fixture(); b[MB_D] = MB_MAX; mb_recheck(b)
246 mb_refuse("negative-product-overflow-preserves-output" as *u8, b, MB_BYTES, "0:-1000" as *u8, ctr,run)
247 b = mb_fixture(); b[MB_V+1] = MB_MAX; mb_recheck(b)
248 mb_refuse("positive-coordinate-add-overflow-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
249 b = mb_fixture(); b[MB_V+1] = 0-MB_MAX-1; b[MB_D] = 0-1; mb_recheck(b)
250 mb_refuse("negative-coordinate-add-overflow-preserves-output" as *u8, b, MB_BYTES, "0:1000" as *u8, ctr,run)
251 b = mb_fixture()
252 mb_refuse_code("empty-channel-preserves-output" as *u8, b, MB_BYTES, ":1" as *u8, MB_USAGE, ctr,run)
253 mb_refuse_code("channel-i64-overflow-preserves-output" as *u8, b, MB_BYTES, "9223372036854775808:0" as *u8, MB_USAGE, ctr,run)
254 mb_refuse_code("positive-weight-i64-overflow-preserves-output" as *u8, b, MB_BYTES, "0:9223372036854775808" as *u8, MB_USAGE, ctr,run)
255 mb_refuse_code("negative-weight-i64-overflow-preserves-output" as *u8, b, MB_BYTES, "0:-9223372036854775809" as *u8, MB_USAGE, ctr,run)
256 let still: *i64 = mb_fixture()
257 var zi: i64 = 0
258 while zi < MB_FACES*MB_AXES { still[MB_D+zi] = 0; zi = zi + 1 }
259 still[MB_M+5] = 0
260 mb_recheck(still)
261 mb_positive("signed-minimum-weight-is-valid-on-zero-deltas" as *u8, "0:-9223372036854775808" as *u8, still, still, ctr,run)
262 mb_positive("signed-maximum-weight-is-valid-on-zero-deltas" as *u8, "0:9223372036854775807" as *u8, still, still, ctr,run)
263 return gv_verdict("NX-MORF-MALFORMED" as *u8, ctr, "exact signed transforms; malformed or overflowing inputs preserve existing destination" as *u8)
264}