raven-image --margin: restore the IHDR size bound before any header-sized allocation, with the 2**32-1 test that pins it

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
Kiko 2026-11-11 22:34:01 +00:00
commit dd3d432573
3 changed files with 5 additions and 2 deletions

View file

@ -80,7 +80,7 @@ the subject also contains (green in a green-eyed character) is untouched except
a rectangle, so the pin cannot ask for a vignette or a round sticker. A subject cannot be asked to stay off the seam: only
the exit code tells you it did not.
Offline test (fake ComfyUI on 127.0.0.1, 158 checks): `python3 tests/test-raven-image.py`.
Offline test (fake ComfyUI on 127.0.0.1, 159 checks): `python3 tests/test-raven-image.py`.
## What it does

View file

@ -160,6 +160,8 @@ def png_decode(data):
if hdr is None or not idat:
raise ValueError("no IHDR or no image data")
w, h, depth, ctype, _, _, interlace = hdr
if not 0 < w * h <= 2 ** 26: # before any allocation sized by the header: 2**32-1 squared would ask for 12 GB and overflow ssize_t
raise ValueError(f"image size {w}x{h} is out of range")
if depth != 8 or ctype not in (2, 6) or interlace:
raise ValueError(f"only 8-bit non-interlaced RGB/RGBA is handled (got depth {depth}, colour type {ctype}, interlace {interlace})")
bpp = 3 if ctype == 2 else 4

View file

@ -307,12 +307,13 @@ def blob(w, h, depth=8, ctype=2, idat=None, il=0):
+ ck(b"IDAT", idat if idat is not None else zlib.compress(b"\0" * (h * (w * 3 + 1)) if w * h < 10 ** 7 else b"")) + ck(b"IEND", b""))
good = mkpng(8, 8, lambda x, y: BG)
bad = bytearray(good); bad[40] ^= 1
for data, what in ((bytes(bad), "flipped byte (CRC)"), (blob(2 ** 21, 2 ** 21), "a header that promises far more than the data"), (blob(8, 8, idat=zlib.compress(b"\0" * (8 * 25 - 1))), "image data shorter than the header says"),
for data, what in ((bytes(bad), "flipped byte (CRC)"), (blob(2 ** 21, 2 ** 21), "a header that promises far more than the data"), (blob(2 ** 32 - 1, 2 ** 32 - 1), "a 2**32-1 square header (must refuse before allocating)"), (blob(8, 8, idat=zlib.compress(b"\0" * (8 * 25 - 1))), "image data shorter than the header says"),
(blob(8, 8, idat=zlib.compress(b"\0" * (8 * 25 + 500))), "image data longer than the header says"), (blob(8, 8, depth=16), "16-bit"),
(blob(8, 8, ctype=3), "palette"), (blob(8, 8, il=1), "interlaced"), (good[:-20], "truncated"),
(good[:8] + struct.pack(">I", 10 ** 6) + good[12:], "chunk length past the end")):
try: mod2.png_decode(data); check(False, f"png_decode refuses {what}")
except (ValueError, zlib.error, struct.error): check(True, "")
except BaseException as e: check(False, f"png_decode refuses {what} cleanly, got {type(e).__name__}")
# size and interior validation, before any request
refused(["--size", "foo", "cap"], "--size is WxH", "--size foo")
refused(["--size", "1000x1024", "cap"], "multiples of 16", "--size not on the grid")