code wiki / (root) / nx_jpegmem_probe.nx

nx_jpegmem_probe.nx source

↩ module page · 95 lines · 3766 B

1// nx_jpegmem_probe.nx -- INSTRUMENT: does nx_jpeg_decode_rgb overrun/leak per call? 2// Decodes the SAME jpeg N times in one process, printing VmRSS after each decode, freeing the 3// caller-visible RGB each round. A flat RSS = the lib cleans up; a climbing RSS = per-call arena 4// growth (the OOM suspect for the 12-decode toon run); ARENA-OVERRUN lines localize the write. 5// usage: nx_jpegmem_probe <file.jpg> <rounds> 6 7import "nx_syscalls.nx" 8import "nx_jpeg_ascii.nx" 9 10func jp_slen(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n } 11func jp_out(s: *u8) -> i64 { sys_write(1, s, jp_slen(s)); return 0 } 12func jp_outn(v: i64) -> i64 { 13 let b: *u8 = sys_mmap(32) 14 var x: i64 = v 15 var n: i64 = 0 16 if x == 0 { b[0] = 48 as u8; n = 1 } else { 17 while x > 0 { b[n] = (48 + (x % 10)) as u8; x = x / 10; n = n + 1 } 18 } 19 var i: i64 = 0 20 while i < n / 2 { let t: u8 = b[i]; b[i] = b[n-1-i]; b[n-1-i] = t; i = i + 1 } 21 sys_write(1, b, n) 22 return 0 23} 24 25func jp_rss() -> i64 { 26 let lp: *i64 = sys_mmap(16) as *i64 27 let b: *u8 = sys_read_file("/proc/self/status" as *u8, lp) 28 let n: i64 = lp[0] 29 if (b as i64) == 0 { return 0 - 1 } 30 var i: i64 = 0 31 while i + 6 < n { 32 if b[i] == (86 as u8) { if b[i+1] == (109 as u8) { if b[i+2] == (82 as u8) { 33 if b[i+3] == (83 as u8) { if b[i+4] == (83 as u8) { 34 var j: i64 = i + 5 35 var v: i64 = 0 36 var seen: i64 = 0 37 var run: i64 = 1 38 while run == 1 { 39 if j >= n { run = 0 } else { 40 let c: i64 = b[j] as i64 41 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48); seen = 1; j = j + 1 } else { 42 if seen == 1 { run = 0 } else { j = j + 1 } 43 if c == 10 { run = 0 } 44 } } else { 45 if seen == 1 { run = 0 } else { j = j + 1 } 46 if c == 10 { run = 0 } 47 } 48 } 49 } 50 return v 51 } } } } } 52 i = i + 1 53 } 54 return 0 - 2 55} 56 57func jp_atoi(s: *u8) -> i64 { 58 var v: i64 = 0 59 var i: i64 = 0 60 while s[i] != (0 as u8) { 61 let c: i64 = s[i] as i64 62 if c >= 48 { if c <= 57 { v = v * 10 + (c - 48) } } 63 i = i + 1 64 } 65 return v 66} 67 68func main(argc: i64, argv: *i64) -> i64 { 69 if argc < 3 { jp_out("usage: nx_jpegmem_probe <file.jpg> <rounds>\n" as *u8); return 2 } 70 let lp: *i64 = sys_mmap(16) as *i64 71 let f: *u8 = sys_read_file(argv[1] as *u8, lp) 72 let flen: i64 = lp[0] 73 if (f as i64) == 0 { jp_out("cannot read input\n" as *u8); return 1 } 74 let rounds: i64 = jp_atoi(argv[2] as *u8) 75 jp_out("rss_before_kb=" as *u8); jp_outn(jp_rss()); jp_out("\n" as *u8) 76 var r: i64 = 0 77 while r < rounds { 78 let pr: *i64 = sys_mmap(8) as *i64 79 let pw: *i64 = sys_mmap(8) as *i64 80 let ph: *i64 = sys_mmap(8) as *i64 81 let rc: i64 = nx_jpeg_decode_rgb(f, flen, pr, pw, ph) 82 jp_out("round=" as *u8); jp_outn(r) 83 jp_out(" rc=" as *u8); jp_outn(rc) 84 jp_out(" w=" as *u8); jp_outn(pw[0]) 85 jp_out(" h=" as *u8); jp_outn(ph[0]) 86 // free with the EXACT allocated length (the lib mmaps width*height*3+16): the previous +64 87 // over-length munmap could clip the start of a neighbouring mapping when the allocation 88 // ended within 48 B of a page boundary -- a real defect, fixed 2026-08-23. 89 if rc == NX_JPEG_ASCII_OK { sys_munmap(pr[0] as *u8, pw[0] * ph[0] * 3 + 16) } 90 jp_out(" rss_kb=" as *u8); jp_outn(jp_rss()) 91 jp_out("\n" as *u8) 92 r = r + 1 93 } 94 return 0 95}