Files
vt1200/harness/mame/pcfwork/make_candidates.py
T
arti 307df67f9d harness/mame: the TFTP PCF loader skips BITMAPS, so the n*4 overflow is not on that path
The TFTP font path loads through 3F96B850 and parses with the metadata
reader 3F97EF00, which handles only PROPERTIES/ACCELERATORS/METRICS/
ENCODINGS and silently skips BITMAPS. A font with num_chars=0x40000001
therefore passes the loader (LOADER-A-SUCCESS) without the field ever
being read, and pcfReadBitmaps (3F984970, multiply 3F985050) is never
entered. pcfReadBitmaps has exactly one caller, 3F98BB70, in the X11
font-request reader 3F98AC20, not the TFTP fetch path.

The 'refused after 1024 bytes' of evil-real.pcf is the METRICS table:
its big-endian compressed count 0x00DF is read little-endian as 57088,
so fosAlloc(57088*16) fails at ~906 bytes; BITMAPS (offset 2024) is
never reached.  Baseline.pcf fails the same way; baseline_le.pcf puts
that one 2-byte field in the order the loader reads it, parses cleanly,
and still ignores the crafted BITMAPS count.

No ROM patch, no check disabled, no serve.py edit.  Baselines unchanged:
no env samples=198, stub samples=53.
2026-10-17 14:14:07 +03:00

57 lines
2.1 KiB
Python

#!/usr/bin/env python3
"""Build the two PCF candidates used in PCF_VALIDATION_REPORT.md.
`baseline_le.pcf` is the project's valid 680-byte font with ONE change: the
compressed-metrics count in the METRICS table is byte-swapped from `00 01`
(big-endian 1, what bdftopcf emits) to `01 00`. The VT1200's font loader reads
that INT16 raw (little-endian), so the stock file is read as 0x0100 = 256
characters and the metrics parse runs off the end of the table. The swap makes
the loader read the intended count of 1. It is a construction of a font the
loader accepts, not a disabled check.
`baseline_le_evil.pcf` is that font with the BITMAPS `num_chars` set to
0x40000001 (the value overflow.lua used) -- to show the loaded path ignores it.
python3 harness/mame/pcfwork/make_candidates.py
"""
import os
import struct
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(HERE)))
sys.path.insert(0, os.path.join(ROOT, "tools"))
import fontgen # noqa: E402
SRC = os.path.join(ROOT, "reference", "fonts", "baseline.pcf")
def main():
with open(SRC, "rb") as fh:
data = bytearray(fh.read())
metrics = fontgen.find_table(bytes(data), fontgen.METRICS)
if metrics is None:
raise SystemExit("baseline.pcf has no METRICS table")
off = metrics["offset"]
fmt = struct.unpack_from("<I", data, off)[0]
if (fmt & 0xFFFFFF00) != 0x100:
raise SystemExit(f"METRICS format 0x{fmt:x} is not compressed (0x100)")
# compressed-metrics body: format CARD32, then count INT16, then INT8 fields
data[off + 4], data[off + 5] = data[off + 5], data[off + 4]
le = os.path.join(HERE, "baseline_le.pcf")
with open(le, "wb") as fh:
fh.write(data)
print(f"wrote {le} ({len(data)} bytes)")
evil = fontgen.set_num_chars(bytes(data), 0x40000001)
evil_path = os.path.join(HERE, "baseline_le_evil.pcf")
with open(evil_path, "wb") as fh:
fh.write(evil)
print(f"wrote {evil_path} ({len(evil)} bytes), BITMAPS num_chars=0x40000001")
if __name__ == "__main__":
main()