#!/usr/bin/env python3 """check_comimage.py -- the image layout is described in exactly one file. Any check that reads a linked .COM has to know where its parts are: the entry jump is three bytes, the header is sixteen, initmem's first bytes sit at ENT_SZ and the header is findable by its own signature. Before tests/comimage.py existed that knowledge lived in three places - comtest.py had a find_header, the independent checker inside run_com_tests.sh had a second copy of it, and check_framedisp.py had a third answer of an entirely different kind: a literal RT_SZ that had drifted from the runtime it claimed to describe. Three copies are three chances to drift, and drift is SILENT here, because each copy is self-consistent on its own terms: every one of them reports confidently and only the world disagrees. So the layout lives in one file, and this asserts that it stays that way: A. comimage.py defines each part exactly once, and imports. Counting rather than merely searching is the point: a rule that matches nothing looks exactly like a rule that passes (the lesson in tests/rt_exec.py's "matched nothing" case), so a deleted definition would otherwise be a green report about a subject nobody examined. B. no other test source defines any of those names. C. every test source that CALLS find_header takes it from comimage rather than from some other consumer: `from comtest import find_header' would be one helper reached through two of them, and the second of those two is a copy waiting to drift. Definitions quoted inside a mutation string are not calls, so `def find_header(d):' written as a case's target does not count - nonvacuity.sh would otherwise fail this audit for naming the very thing it is breaking. Scope, stated so this is not read as more than it is ---------------------------------------------------- This cannot see a check that HAND-ROLLS the layout from literals - check_8086 used to write `hdr = 3 + rt_size', which defines none of these names and would have passed here untouched. Numbers written inline are caught a different way: check_8086.program_code_region and check_framedisp.main both state the layout twice, from two independent sources (the probe-measured runtime size against the header's own equation; the entry jump against the header's end), and require the two to agree. A disagreement is reported instead of swept, and tests/nonvacuity.sh turns each of those red on purpose. Usage: check_comimage.py (from shell/) """ import os import re import sys HERE = os.path.dirname(os.path.abspath(__file__)) COMIMAGE = os.path.join(HERE, "comimage.py") # The names that make up the layout of a linked image. LAYOUT = ["ENT_SZ", "HDR_SZ", "LOAD_BIAS", "HEAD", "HDR_DS_WORD", "HDR_HEAP_WORD"] # rt_exec.py states a load bias of its own, and deliberately so: the address # space it works in is the boot image IT builds (see build_image, and # exec/rtdrv.s, which carries a .set of the same value for the same reason). # Those two are independent statements checked against each other by the cases # failing if they disagree - and rtdrv.s cannot import a Python module. It is a # different artefact's bias, not a copy of this one. EXEMPT = {("rt_exec.py", "LOAD_BIAS")} DEF_FN = re.compile(r"^\s*def\s+find_header\b") IMPORTS = re.compile(r"^\s*(?:import\s+comimage\b|from\s+comimage\s+import\b)") # A CALL, not a definition. The lookbehind is what lets nonvacuity.sh quote # `def find_header(d):' as its mutation target without this audit reporting the # harness itself as a second copy of the helper. MENTIONS = re.compile(r"(?