Repository navigation
fix(corekit): signed NumberField decode, zero-length PayloadField, PCAP trailing bytes and empty Raw - #1331
Conversation
|
Cross-review verdict on
Three corrections for the PR body. (1) The identical-digest claim is vacuously true and should not be cited as evidence: per-frame Confirmed as flagged: |
…AP trailing bytes and empty Raw - NumberField.post_process sign-extends after masking for a signed field, mirroring pre_process, so a resolved Int32Field reads ffffffff as -1. - Schema.unpack treats only a negative PayloadField length as unset; a computed zero is an empty payload and no longer swallows later fields. - PCAP Frame.unpack raises StreamEOFError when fewer than 16 octets are left, so a partial trailing record ends extraction cleanly. - Raw declares its buffer length, so Raw(b"") parses like Raw(packet=b""). Closes #1274 Closes #1275 Closes #1265 Closes #1285
8bfaffa to
51d3e72
Compare
|
The added subtest closes the coverage gap the review named — it pins the unset-length case and fails without the fix (3 Two corrections to my own earlier comment, both from re-derivation rather than relay:
The one-directional widening now rests on a derivation rather than a failed search: the new read count is |
Searched for similar pull requests
Followed the coding style (
make pylint,make mypy,make isort): run on the 4 source files with the Makefile flags; isort clean, no pylint/mypy finding on a changed linemake testpasses, and a test case covers the change: the 4 new modules, 28 neighbouring modules,run_unittest_leg.py protocols/internet(503 OK),protocols --exclude protocols/internet(857 OK),foundation(483 OK),pytest tests/project(389 passed)Added a changelog entry — N/A, added centrally
fix— corrects a defectCloses #1274
Closes #1275
Closes #1265
Closes #1285
#1274 — signed
NumberFielddecodes as unsignedpost_processmasked with_bit_maskand returned, so once__call__had set that mask — as it does for every field inside aSchema— a signed field came back as the unsigned pattern. It now sign-extends after masking, mirroringpre_process.Crafted captures carrying a negative value, against
origin/mainat11ae68ebf:origin/mainif_tzone = -3600ValueError: offset must be a timedelta strictly between -timedelta(hours=24) and timedelta(hours=24)-01:00if_tsoffset = -5OverflowError: timestamp out of range for platform time_t1→-4thiszone = -3600thiszone=4294963696-3600, rebuilds byte-exactThe two PCAP-NG cases also crash
origin/maininjson,plistandtreedumps, and all three dump cleanly here. The PCAP case does not crash on either side — it is a wrong-value bug, not a crash.The fixture captures do not cover this path at all, so they are not evidence either way: all 23 carry
thiszone,if_tzoneandif_tsoffsetof0, andsection_lengthof-1reached through the all-ones value thatschema/misc/pcapng.py:959already special-cased. Per-frameinfodigests being unchanged (below) is therefore vacuously true for this issue.#1275 — a computed
PayloadFieldlength of 0 swallows the restpayload_length = length or packet['__length__']read a computed0as "unset". Only a negative length is unset now, and it is bounded bymax(__length__, 0).origin/mainn=0, then a 2-octet fieldbody=b'ab' tail=b'\x00\x00'body=b'' tail=b'ab'__length__=3, 8 octets in the streambody=b'abcdefgh', stream at 9,__length__left at 3 — larger than the 2 it held before the readbody=b'ab', stream at 3,__length__left at 0The change is one-directional: it can only truncate. The new read count is
max(__length__, 0), which is never more than theread(-1)it replaces, so no input can be made to read further than before. The one behaviour change for an unset payload is that it now stops at__length__instead of running to the end of the stream, and yieldsb''when__length__is 0 or less. No protocol in the tree hits that: across the layers nothing moved (see the digests below).Earlier drafts of this description said a negative length other than
-1used to raiseValueError. That is wrong for in-memory streams —BytesIO.read(-2)reads everything and raises nothing. It raised only on a real file object, which is #1265's case.#1265 — 3 trailing bytes crash
extractFrame.unpacknow raises a quietStreamEOFErrorwhen fewer than 16 octets are left, the floor__length_hint__already reports, so extraction ends with the frames it has — the same signal the PCAP-NG reader has used since #678.examples/captures/test.pcapplusb'\x00\x01\x02':ValueError: read length must be non-negative or -1before, 34 frames after.Both files are load-bearing. With only the
schema.pyhalf applied, a tail of 1, 3 or 15 octets yields unbounded phantom frames — still producing at a probe cap of 200. A tail of 16 or more is above the floor and parses as an ordinary empty record, unchanged fromorigin/main.#1285 —
Raw(b"")Rawnow declares its buffer's length instead of leaving it to be derived, since a derived0isprepare's end-of-stream signal.Raw(b"")raisedStreamEOFError; it now parses, and agrees withRaw(packet=b"").Digests, and what they do and do not show
Per-frame
infodigests plus the PCAP global header over all 23examples/capturesfiles: 0 of 23 differ, after each fix alone and after all four. That rules out collateral damage to the parsed output of every fixture, which is what it is cited for. It says nothing about #1274, for the coverage reason above.Each new test fails with its fix reverted — for #1265, with either half reverted.
Notes
schema/misc/pcapng.py:959(section_length == 0xFFFF…→-1) is now redundant, since the field decodes to-1itself. Left alone: that file belongs to another worker in this wave.intwhere it returned the unsigned pattern, andSchema.unpackleaves a correctly decremented__length__for an unset payload.if_tzonestill raises a rawValueError, and out-of-rangeif_tsoffseta rawOSError/OverflowErrorfromfromtimestamp, which catches onlyValueError. This change shiftsif_tsoffset = -2**63fromOverflowErrortoOSError. Being filed separately.