code wiki / (root) / nx_verify_port_core.nx

nx_verify_port_core.nx source

↩ module page · 150 lines · 6820 B

1// nx_verify_port_core.nx -- the portability linter's SCANNER (importable; nx_verify's `portability` verb 2// + nx_portability_gate both use THIS one implementation, DRY). A LOGIC-layer source must not touch the 3// OS directly: raw "/proc" "/sys" "/dev" "/tmp" string literals or raw __syscall( outside the seams. 4// //-comments are skipped (docs may NAME the law); strings are scanned (couplings live in strings). 5// license_tier: ORIGINAL 6import "nx_syscalls.nx" 7 8const VP_NL: i64 = 10 9const VP_ASCII_0: i64 = 48 // '0' (decimal print) 10const VP_COMMENT_LEN: i64 = 2 // "//" is two chars 11 12func vp_puts(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } sys_write(1, s, n); return 0 } 13func vp_putn(v: i64) -> i64 { 14 if v == 0 { sys_write(1, "0" as *u8, 1); return 0 } 15 var m: i64 = v; if m < 0 { sys_write(1, "-" as *u8, 1); m = 0 - m } 16 let d: *u8 = sys_mmap(24); var k: i64 = 0 17 while m > 0 { d[k] = (VP_ASCII_0 + (m % 10)) as u8; m = m / 10; k = k + 1 } 18 let o: *u8 = sys_mmap(24); var i: i64 = 0 19 while i < k { o[i] = d[k-1-i]; i = i + 1 } sys_write(1, o, k) 20 return 0 21} 22// NUL-terminated lit matches buf at i (bounded by n)? 23func vp_matchat(buf: *u8, i: i64, n: i64, lit: *u8) -> i64 { 24 var k: i64 = 0 25 while lit[k] != (0 as u8) { if i + k >= n { return 0 } if buf[i+k] != lit[k] { return 0 } k = k + 1 } 26 return 1 27} 28// substring: does NUL-terminated needle appear in NUL-terminated s? 29func vp_name_has(s: *u8, needle: *u8) -> i64 { 30 var i: i64 = 0 31 while s[i] != (0 as u8) { 32 var k: i64 = 0; var m: i64 = 1 33 while needle[k] != (0 as u8) { if s[i+k] == (0 as u8) { m = 0; k = k + 1 } else { if s[i+k] != needle[k] { m = 0 } k = k + 1 } } 34 if m == 1 { return 1 } 35 i = i + 1 36 } 37 return 0 38} 39const VP_RD_CAP: i64 = 1048576 // per-file scan cap 40const VP_C_SCANNED: i64 = 0 // census counts[] slots 41const VP_C_COUPLED: i64 = 1 42const VP_C_HITS: i64 = 2 43const VP_C_EXEMPT: i64 = 3 44const VP_PATH_CAP: i64 = 1024 45const VP_DENT_BUF: i64 = 65536 // getdents64 batch (proven sizing) 46 47// bounded whole-file read (no fstat dependence -- procfs-safe pattern) 48func vp_read(path: *u8, buf: *u8, cap: i64) -> i64 { 49 let fd: i64 = sys_openat_rd(path) 50 if fd < 0 { return 0 } 51 var got: i64 = 0 52 var go: i64 = 1 53 while go == 1 { let r: i64 = sys_read(fd, (buf as i64 + got) as *u8, cap - got); if r > 0 { got = got + r; if got >= cap { go = 0 } } else { go = 0 } } 54 sys_close(fd) 55 return got 56} 57// structural exemption by filename (the seams + fixtures where OS-access legitimately lives) 58func vp_exempt_name(name: *u8) -> i64 { 59 if vp_name_has(name, "nx_os_" as *u8) == 1 { return 1 } 60 if vp_name_has(name, "nx_syscalls" as *u8) == 1 { return 1 } 61 if vp_name_has(name, "_gate" as *u8) == 1 { return 1 } 62 if vp_name_has(name, "_core.nx" as *u8) == 1 { return 1 } 63 return 0 64} 65// does NUL-terminated s end with NUL-terminated suf? 66func vp_ends(s: *u8, suf: *u8) -> i64 { 67 var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } 68 var m: i64 = 0; while suf[m] != (0 as u8) { m = m + 1 } 69 if m > n { return 0 } 70 var i: i64 = 0 71 while i < m { if s[n - m + i] != suf[i] { return 0 } i = i + 1 } 72 return 1 73} 74 75// count OS-coupling hits in buf[0..n); //-comments skipped, string literals scanned 76func vp_scan(buf: *u8, n: i64) -> i64 { 77 var count: i64 = 0 78 var i: i64 = 0 79 var incomm: i64 = 0 80 while i < n { 81 if buf[i] == (VP_NL as u8) { incomm = 0; i = i + 1 } else { 82 if incomm == 1 { i = i + 1 } else { 83 if vp_matchat(buf, i, n, "//" as *u8) == 1 { incomm = 1; i = i + VP_COMMENT_LEN } else { 84 var hit: i64 = 0 85 if vp_matchat(buf, i, n, "\"/proc" as *u8) == 1 { hit = 1 } 86 if vp_matchat(buf, i, n, "\"/sys" as *u8) == 1 { hit = 1 } 87 if vp_matchat(buf, i, n, "\"/dev" as *u8) == 1 { hit = 1 } 88 if vp_matchat(buf, i, n, "\"/tmp" as *u8) == 1 { hit = 1 } 89 if vp_matchat(buf, i, n, "__syscall(" as *u8) == 1 { hit = 1 } 90 if hit == 1 { count = count + 1 } 91 i = i + 1 92 } } } 93 } 94 return count 95} 96 97// TREE CENSUS: scan every *.nx in dir (non-recursive; call per dir). Prints each COUPLED logic file 98// (the burn-down list) + a summary. counts[0]=scanned logic, [1]=coupled files, [2]=total couplings, 99// [3]=exempt(seams/gates). Returns coupled-file count. ONE process -- no per-file spawn cost. 100// (defined AFTER vp_scan: declare-before-use) 101func vp_census(dir: *u8, counts: *i64) -> i64 { 102 let fd: i64 = sys_openat_rd(dir) 103 if fd < 0 { vp_puts("vp_census: cannot open dir\n" as *u8); return 0 - 1 } 104 let dbuf: *u8 = sys_mmap(VP_DENT_BUF) 105 let path: *u8 = sys_mmap(VP_PATH_CAP) 106 let fbuf: *u8 = sys_mmap(VP_RD_CAP) 107 var scanned: i64 = 0 108 var coupled: i64 = 0 109 var hits_total: i64 = 0 110 var exempt: i64 = 0 111 var run: i64 = 1 112 while run == 1 { 113 let n: i64 = sys_getdents64(fd, dbuf, VP_DENT_BUF) 114 if n <= 0 { run = 0 } else { 115 var off: i64 = 0 116 while off < n { 117 let rec: *u8 = ((dbuf as i64 + off) as *u8) 118 let reclen: i64 = dirent_reclen(rec) 119 if reclen <= 0 { off = n } else { 120 let name: *u8 = dirent_name(rec) 121 if vp_ends(name, ".nx" as *u8) == 1 { 122 if vp_exempt_name(name) == 1 { exempt = exempt + 1 } else { 123 var o: i64 = 0 124 var i: i64 = 0 125 while dir[i] != (0 as u8) { path[o] = dir[i]; o = o + 1; i = i + 1 } 126 if o > 0 { if path[o-1] != (47 as u8) { path[o] = 47 as u8; o = o + 1 } } 127 i = 0 128 while name[i] != (0 as u8) { path[o] = name[i]; o = o + 1; i = i + 1 } 129 path[o] = 0 as u8 130 let fn: i64 = vp_read(path, fbuf, VP_RD_CAP - 1) 131 if fn > 0 { 132 scanned = scanned + 1 133 let h: i64 = vp_scan(fbuf, fn) 134 if h > 0 { 135 coupled = coupled + 1 136 hits_total = hits_total + h 137 vp_puts(" COUPLED " as *u8); vp_puts(name); vp_puts(" hits=" as *u8); vp_putn(h); vp_puts("\n" as *u8) 138 } 139 } 140 } 141 } 142 off = off + reclen 143 } 144 } 145 } 146 } 147 sys_close(fd) 148 counts[VP_C_SCANNED] = scanned; counts[VP_C_COUPLED] = coupled; counts[VP_C_HITS] = hits_total; counts[VP_C_EXEMPT] = exempt 149 return coupled 150}