qemu and build: review fixes across the rig driver, boot script, and fetch helpers

Bounded waits and validated arguments in run.sh and ui-drive.sh, a seeded
settings directory and root-only staged rootfs permissions with their own
tests, qmp.py and imgtools.py hardening, the fetch scripts checking what they
download, and ASCII typography throughout. Each fix carries its test under
qemu/tests or tests/.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01N3G6m9Aw5RyVY4ZowtKzEj
This commit is contained in:
Noah
2026-09-09 19:17:54 -06:00
co-authored by Claude Fable 5.1
parent bda6c6c633
commit 2b6e8a2098
24 changed files with 1823 additions and 137 deletions
+48 -58
View File
@@ -35,11 +35,10 @@ import json
from PIL import Image, ImageFilter
# occupancy thresholds for structural(): a downsampled cell counts as
# "occupied" if it is meaningfully brighter than black, or sits on an edge.
# Both are 0..255 greyscale/edge-magnitude averages over the cell.
# structural(): a cell is occupied when its grey is this far from the crop's
# median (its background) or its FIND_EDGES energy exceeds the edge threshold.
# occupancy thresholds for structural(): a cell is occupied when its grey is
# this far from the crop's median (its background), or its FIND_EDGES energy
# exceeds the edge threshold. Both are 0..255 greyscale/edge-magnitude
# averages over the cell.
# Validated on real captures: a switch knob left/right differs in 240/256
# cells, a dark card's icon and text stand out from its (7,13,29) ground.
DEVIATION_THRESHOLD = 28
@@ -53,64 +52,31 @@ EDGE_THRESHOLD = 24
def load_ppm(path):
"""Read a binary PPM (P6), return (w, h, rgb_bytes).
QEMU's screendump writes a comment-free header ("P6\\nW H\\n255\\n"
then raw bytes) but the token reader here handles the general P6
grammar -- whitespace runs and '#' comments -- since that costs
nothing extra and means any other producer of P6 files just works.
Delegates to Pillow's own P6 decoder (Image.open, format auto-detected
from the magic) instead of re-parsing the PPM grammar by hand: skipping
whitespace runs and '#' comments, and normalising any maxval to 8-bit,
are Pillow's problem here, not ours. convert("RGB") guarantees the
tightly-packed 3-bytes-per-pixel layout every caller in this file
assumes regardless of the source channel depth.
"""
with open(path, "rb") as f:
data = f.read()
def skip_ws_comments(p):
while p < len(data):
c = data[p]
if c in b" \t\r\n":
p += 1
elif c == ord("#"):
while p < len(data) and data[p] != ord("\n"):
p += 1
else:
break
return p
def read_token(p):
p = skip_ws_comments(p)
start = p
while p < len(data) and data[p] not in b" \t\r\n":
p += 1
return data[start:p], p
pos = 0
magic, pos = read_token(pos)
if magic != b"P6":
raise ValueError(f"{path}: not a P6 PPM (magic={magic!r})")
w_tok, pos = read_token(pos)
h_tok, pos = read_token(pos)
maxval_tok, pos = read_token(pos)
w, h, maxval = int(w_tok), int(h_tok), int(maxval_tok)
if maxval != 255:
raise ValueError(f"{path}: unsupported PPM maxval {maxval} (only 255 handled)")
# exactly one whitespace byte separates the header from the binary data
pos += 1
need = w * h * 3
pixels = data[pos:pos + need]
if len(pixels) != need:
raise ValueError(f"{path}: truncated PPM, want {need} bytes got {len(pixels)}")
return w, h, pixels
with Image.open(path) as im:
im = im.convert("RGB")
return im.width, im.height, im.tobytes()
def crop(img, x, y, w, h):
"""Crop (W,H,rgb) to the x,y,w,h box, return a new (w,h,rgb) image."""
"""Crop (W,H,rgb) to the x,y,w,h box, return a new (w,h,rgb) image.
The bounds check stays explicit and fails loudly (see main()'s own
comment on that) rather than delegating to PIL's crop, which silently
zero-pads a box that runs outside the source image instead of raising --
exactly the kind of stale/mistyped region box this check exists to catch.
"""
width, height, data = img
if x < 0 or y < 0 or w <= 0 or h <= 0 or x + w > width or y + h > height:
raise ValueError(f"crop box {x},{y},{w}x{h} outside image {width}x{height}")
row_bytes = w * 3
out = bytearray(h * row_bytes)
for row in range(h):
src_off = ((y + row) * width + x) * 3
dst_off = row * row_bytes
out[dst_off:dst_off + row_bytes] = data[src_off:src_off + row_bytes]
return w, h, bytes(out)
cropped = _to_pil(img).crop((x, y, x + w, y + h))
return w, h, cropped.tobytes()
def _to_pil(img):
@@ -188,7 +154,7 @@ def phash(img):
def hamming(a, b):
"""Bit-differences between two phash ints."""
return bin(a ^ b).count("1")
return (a ^ b).bit_count()
# ---------------------------------------------------------------------------
@@ -241,7 +207,7 @@ def _median_grey(grey):
def _structural_diff(a, b):
"""Count of differing bits between two 32-byte occupancy masks."""
return sum(bin(x ^ y).count("1") for x, y in zip(a, b))
return (int.from_bytes(a, "big") ^ int.from_bytes(b, "big")).bit_count()
# ---------------------------------------------------------------------------
@@ -405,6 +371,10 @@ def cmd_bench(argv):
print(f"bench: {cw}x{ch} region, n={n} iterations")
for label, fn in (("phash", lambda: phash(region)),
("structural", lambda: structural(region))):
for _ in range(5):
fn() # warm up: first call can carry one-off costs (e.g. module-
# level caches settling) that don't belong in the steady-state
# population below
samples = timeit.repeat(fn, repeat=n, number=1)
lo, p50, p95, hi = percentiles(samples)
print(f" {label:<10} min={lo * 1000:7.3f}ms p50={p50 * 1000:7.3f}ms "
@@ -493,6 +463,26 @@ def selftest():
check("crop keeps the drawn pixel in place",
cropped[2][px_off:px_off + 3] == bytes((220, 20, 20)))
# a header QEMU never writes but the P6 grammar allows: a '#'
# comment line and a non-255 maxval. Pillow's decoder (load_ppm no
# longer hand-parses the header) must still read it correctly.
odd_path = os.path.join(tmp, "odd-header.ppm")
with open(odd_path, "wb") as f:
f.write(b"P6\n# generated for a selftest, not by QEMU\n2 2\n100\n")
f.write(bytes((100, 0, 0, 0, 100, 0, 0, 0, 100, 100, 100, 100)))
ow, oh, odata = load_ppm(odd_path)
check("load_ppm reads width/height past a comment line", (ow, oh) == (2, 2))
check("load_ppm scales a non-255 maxval channel to 8-bit",
odata[0:3] == bytes((255, 0, 0)))
# crop box outside the image must still fail loudly, not silently
# zero-pad the way PIL's own Image.crop does
try:
crop((bw, bh, bdata), bw - 4, bh - 4, 32, 32)
check("crop rejects a box past the image edge", False)
except ValueError:
check("crop rejects a box past the image edge", True)
# _dct2d_32's _DCT_KEEP truncation must land on the exact same
# coefficients an untruncated 32x32 DCT would produce
small = _to_pil((bw, bh, bdata)).convert("L").resize((32, 32), Image.LANCZOS)