From 3dc3976a2cc8e4f583f51b78a9a16a8ad8421ee9 Mon Sep 17 00:00:00 2001 From: I-mho Date: Mon, 5 Oct 2026 01:48:06 +0900 Subject: [PATCH] fix(ash): raise ParsingError instead of asserting on oversized frame payload DataFrame.from_bytes() derandomizes the payload via _randomize(), which asserted len(data) <= len(PSEUDO_RANDOM_DATA_SEQUENCE) (256 bytes). A CRC-valid frame with a payload longer than 256 bytes therefore escaped with an uncaught AssertionError instead of ParsingError, and under `python -O` (assertions stripped) the payload was silently truncated to 256 bytes. Raise ParsingError on oversized payloads so malformed input is rejected consistently. Fixes #762 Co-Authored-By: hw1186 --- bellows/ash.py | 6 +++++- tests/test_ash.py | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/bellows/ash.py b/bellows/ash.py index 48b492ca..14627281 100644 --- a/bellows/ash.py +++ b/bellows/ash.py @@ -177,7 +177,11 @@ class DataFrame(AshFrame): @staticmethod def _randomize(data: bytes) -> bytes: - assert len(data) <= len(PSEUDO_RANDOM_DATA_SEQUENCE) + if len(data) > len(PSEUDO_RANDOM_DATA_SEQUENCE): + raise ParsingError( + f"Frame payload is too long: {len(data)} >" + f" {len(PSEUDO_RANDOM_DATA_SEQUENCE)} bytes" + ) return bytes([a ^ b for a, b in zip(data, PSEUDO_RANDOM_DATA_SEQUENCE)]) @classmethod diff --git a/tests/test_ash.py b/tests/test_ash.py index 8b116926..0a4bebec 100644 --- a/tests/test_ash.py +++ b/tests/test_ash.py @@ -197,6 +197,18 @@ def test_frame_parsing_errors(): assert ash.RstFrame.from_bytes(b"\xC0\xAB\xCD") +def test_data_frame_payload_too_long(): + seq_len = len(ash.PSEUDO_RANDOM_DATA_SEQUENCE) + + # A payload of exactly the sequence length still parses. + ash.DataFrame.from_bytes(ash.AshFrame.append_crc(bytes([0x00]) + bytes(seq_len))) + + # One byte longer must raise ParsingError, not an uncaught AssertionError. + too_long = ash.AshFrame.append_crc(bytes([0x00]) + bytes(seq_len + 1)) + with pytest.raises(ash.ParsingError, match=r"too long"): + ash.DataFrame.from_bytes(too_long) + + def test_rst_frame(): assert ash.RstFrame() == ash.RstFrame() assert ash.RstFrame().to_bytes() == b"\xC0\x38\xBC"