nx_contentdiff.nx source
↩ module page · 161 lines · 5806 B
1// nx_contentdiff.nx -- THE PROMOTE RULER. Answers one question: does the candidate binary still contain
2// everything the LIVE binary contains?
3//
4// WHY (debts 1785452162, 1785526315, 1785526809): the ecosystem has ~703 deployed organs awaiting a
5// rebuild, and the gate guarding that queue was BYTE SIZE. Size is uninformative IN BOTH DIRECTIONS,
6// proven twice by measurement:
7// SHRINK is not regression -- 16 live organs had LARGER .prev files, yet the smaller live binaries
8// were string SUPERSETS (lost_from_live=0). Restoring the bigger ones would have BEEN the regression.
9// GROWTH is not improvement -- nx_law_warden rebuilt GREW 161951 -> 186696 bytes while losing three
10// whole detectors (laws_measured 11 -> 8, enforced_permil 1000 -> 727).
11// A gate keyed on bytes is therefore wrong about half the time and cannot tell you which half.
12//
13// THE RULER: printable content. Every printable run of >= CD_MINLEN bytes in the LIVE binary must still
14// be findable somewhere in the candidate. Anything missing is capability the rebuild would DESTROY.
15// Searching the candidate's RAW BYTES (not a re-extracted string set) is deliberate and stricter: a
16// string that survived but got tokenized differently still counts as present, so a MISS is a real miss.
17//
18// FAIL-CLOSED: unreadable input is RED, never "clean". Verdict GREEN iff lost_from_live == 0.
19// NOT DEDUPED, and it says so in the output: runs are counted as encountered, so the counts are
20// occurrence counts and lost>0 is the signal -- declaring that beats a silent, prettier number.
21//
22// nx_contentdiff <live-elf> <candidate-elf>
23//
24// license_tier: ORIGINAL No hw writes (Rule 26). expect_exit: 0
25import "nx_syscalls.nx"
26import "nx_gate_verdict.nx"
27
28const CD_CAP: i64 = 4194304
29const CD_MINLEN: i64 = 6
30const CD_PRINT_LO: i64 = 32
31const CD_PRINT_HI: i64 = 126
32const CD_SHOW: i64 = 8
33const CD_WORD: i64 = 8
34const CD_SLOTS: i64 = 8
35const CD_S_RUNS: i64 = 0
36const CD_S_LOST: i64 = 1
37const CD_S_SHOWN: i64 = 2
38
39func cd_slurp(path: *u8, buf: *u8, cap: i64) -> i64 {
40 let fd: i64 = sys_openat_rd(path)
41 if fd < 0 { return 0 - 1 }
42 var tot: i64 = 0
43 var go: i64 = 1
44 while go == 1 {
45 let r: i64 = sys_read(fd, ((buf as i64) + tot) as *u8, cap - tot)
46 if r <= 0 { go = 0 } else { tot = tot + r }
47 if tot >= cap { go = 0 }
48 }
49 sys_close(fd)
50 return tot
51}
52
53func cd_is_print(c: i64) -> i64 {
54 if c < CD_PRINT_LO { return 0 }
55 if c > CD_PRINT_HI { return 0 }
56 return 1
57}
58
59// is hay[0..hn) containing needle bytes hay2[s..s+len)?
60func cd_contains(hay: *u8, hn: i64, ndl: *u8, ns: i64, nl: i64) -> i64 {
61 if nl <= 0 { return 1 }
62 if nl > hn { return 0 }
63 var i: i64 = 0
64 while i + nl <= hn {
65 var k: i64 = 0
66 var ok: i64 = 1
67 while k < nl {
68 if hay[i+k] != ndl[ns+k] { ok = 0; k = nl } else { k = k + 1 }
69 }
70 if ok == 1 { return 1 }
71 i = i + 1
72 }
73 return 0
74}
75
76func main(argc: i64, argv: *i64) -> i64 {
77 if argc < 3 {
78 gv_puts("usage: nx_contentdiff <live-elf> <candidate-elf>\n" as *u8)
79 sys_exit(2)
80 return 2
81 }
82 let livep: *u8 = argv[1] as *u8
83 let candp: *u8 = argv[2] as *u8
84
85 let a: *u8 = sys_mmap(CD_CAP)
86 let b: *u8 = sys_mmap(CD_CAP)
87 let an: i64 = cd_slurp(livep, a, CD_CAP)
88 let bn: i64 = cd_slurp(candp, b, CD_CAP)
89
90 gv_puts("=== NX-CONTENTDIFF live=" as *u8)
91 gv_puts(livep)
92 gv_puts(" candidate=" as *u8)
93 gv_puts(candp)
94 gv_puts(" ===\n" as *u8)
95
96 if an <= 0 {
97 gv_puts("verdict=RED rule=live-unreadable\n" as *u8)
98 sys_exit(1)
99 return 1
100 }
101 if bn <= 0 {
102 gv_puts("verdict=RED rule=candidate-unreadable\n" as *u8)
103 sys_exit(1)
104 return 1
105 }
106
107 let st: *i64 = sys_mmap(CD_SLOTS * CD_WORD) as *i64
108 var z: i64 = 0
109 while z < CD_SLOTS { st[z] = 0; z = z + 1 }
110
111 var i: i64 = 0
112 while i < an {
113 if cd_is_print(a[i] as i64) == 1 {
114 // walk to the end of this printable run. Flag-terminated: a sentinel assignment would
115 // lose the real index, which is what the first draft of this loop got wrong.
116 var end: i64 = i
117 var scanning: i64 = 1
118 while scanning == 1 {
119 if end >= an { scanning = 0 } else {
120 if cd_is_print(a[end] as i64) == 1 { end = end + 1 } else { scanning = 0 }
121 }
122 }
123 let rl: i64 = end - i
124 if rl >= CD_MINLEN {
125 st[CD_S_RUNS] = st[CD_S_RUNS] + 1
126 if cd_contains(b, bn, a, i, rl) == 0 {
127 st[CD_S_LOST] = st[CD_S_LOST] + 1
128 if st[CD_S_SHOWN] < CD_SHOW {
129 st[CD_S_SHOWN] = st[CD_S_SHOWN] + 1
130 gv_puts(" LOST: " as *u8)
131 sys_write(1, ((a as i64) + i) as *u8, rl)
132 gv_puts("\n" as *u8)
133 }
134 }
135 }
136 i = end
137 } else {
138 i = i + 1
139 }
140 }
141
142 gv_puts("\nlive_bytes=" as *u8)
143 gv_num(an)
144 gv_puts(" candidate_bytes=" as *u8)
145 gv_num(bn)
146 gv_puts("\nruns_scanned=" as *u8)
147 gv_num(st[CD_S_RUNS])
148 gv_puts(" lost_from_live=" as *u8)
149 gv_num(st[CD_S_LOST])
150 gv_puts(" minlen=" as *u8)
151 gv_num(CD_MINLEN)
152 gv_puts("\ndeduped=0 (occurrence counts, declared not hidden)\n\n" as *u8)
153
154 let ctr: *i64 = gv_ctr()
155 gv_check("C1 live binary readable", an > 0, ctr)
156 gv_check("C2 candidate binary readable", bn > 0, ctr)
157 gv_check("C3 no printable content lost from live", st[CD_S_LOST] == 0, ctr)
158 let rc: i64 = gv_verdict("CONTENTDIFF", ctr, "candidate retains every printable run the live binary has")
159 sys_exit(rc)
160 return rc
161}