code wiki / _hdl_build / nx_doc_ubscan.nx

nx_doc_ubscan.nx source

↩ module page · 45 lines · 2616 B

1// nx_doc_ubscan.nx -- a static detector for the UNDEFINED-BEHAVIOR pattern LM-031: an inline cast-then-index 2// `(EXPR as *T)[i]` SILENTLY MISCOMPILES in NishiLang, returning a garbage pointer-sized value with NO error (it 3// cost a real bug: nx_vizsla_notes nv_occ_window returned a bogus deadline year; nx_doc_demo_const ran exit 156 for 4// expected 99). The fix-by-construction (LM-031): bind the cast to a local FIRST, then index. This detector flags 5// the dangerous inline form so it's caught BEFORE it corrupts data -- the build-resolve loop can't (it's a silent 6// miscompile, no build failure). LINEAGE: this is the NISHI RECYCLER's CONVERT of the undefined-behavior critique 7// (knowledge/fetched/recyc_crit_ub.raw) that nx_recycler_extract flagged as APPLIES-to-us -> turned into real 8// hardening. READ-ONLY (no rewrite). Doctor-family sibling of nx_doc_kwscan / nx_doc_mainscan. license_tier: ORIGINAL 9import "nx_syscalls.nx" 10import "nx_doc_heal_let.nx" 11 12func ub_skipws(src: *u8, n: i64, p0: i64) -> i64 { 13 var p: i64=p0; var go: i64=1 14 while go==1 { if p<n { if src[p]==(32 as u8){p=p+1} else { if src[p]==(9 as u8){p=p+1} else { if src[p]==(10 as u8){p=p+1} else {go=0} } } } else {go=0} } 15 return p 16} 17// 1 iff a cast-then-index `as *<ident> ) [` pattern starts at the `as` token at position i. 18func ub_castindex_at(src: *u8, n: i64, i: i64) -> i64 { 19 if i+2 > n { return 0 } 20 if src[i]!=(97 as u8) { return 0 } // 'a' 21 if src[i+1]!=(115 as u8) { return 0 } // 's' 22 if i>0 { if dhl_isident(src[i-1] as i64)==1 { return 0 } } // 'as' is a whole word 23 if i+2<n { if dhl_isident(src[i+2] as i64)==1 { return 0 } } 24 var p: i64 = ub_skipws(src, n, i+2) 25 if p>=n { return 0 } 26 if src[p]!=(42 as u8) { return 0 } // '*' 27 p = ub_skipws(src, n, p+1) 28 if p>=n { return 0 } 29 if dhl_isident(src[p] as i64)==0 { return 0 } // the pointed-to type name 30 var go: i64=1 31 while go==1 { if p<n { if dhl_isident(src[p] as i64)==1 { p=p+1 } else { go=0 } } else { go=0 } } 32 p = ub_skipws(src, n, p) 33 if p>=n { return 0 } 34 if src[p]!=(41 as u8) { return 0 } // ')' 35 p = ub_skipws(src, n, p+1) 36 if p>=n { return 0 } 37 if src[p]!=(91 as u8) { return 0 } // '[' -> the dangerous inline index 38 return 1 39} 40// byte offset of the first inline cast-then-index in src[0..n), or -1. 41func ub_scan(src: *u8, n: i64) -> i64 { 42 var i: i64=0 43 while i<n { if ub_castindex_at(src, n, i)==1 { return i } i=i+1 } 44 return 0-1 45}