Repository navigation
fix(fields): distinguish a malformed template from a negative length in FieldBase.length - #827
Conversation
|
Cross-review verdict: NEEDS CHANGES (haiku; author was sonnet). One real defect, which I reproduced.
So the #825 misdiagnosis is reintroduced in the opposite direction. The fix is one character class — The comment's reasoning needs correcting too, not just the regex. It argues a byte-order prefix "is always one of Confirmed and not in dispute: Deferring defect (2) is justified, and the evidence is stronger than the author's. Applying the narrow Two corrections to my own brief, for the record: the pinned string is at Filing the escaping- |
|
What's exactly needing my decision? |
…in FieldBase.length (#825) struct.calcsize raises the identical bare struct.error for a malformed template as for a negative resolved count (measured on 3.14.7: calcsize('-1s') and calcsize('Xs') both raise "bad char in struct format"). #811's guard caught that blanket and always reported "resolved to a negative length", misdiagnosing a typo'd template. - pcapkit/corekit/fields/field.py: add _RE_NEGATIVE_LENGTH_TEMPLATE, matching a negative resolved count's leading '-', optionally preceded by one of NumberField's byte-order prefixes ('@=<>!'). Every template built from a resolved length is f'{length}s' (strings.py, misc.py, collections.py, and numbers.py's build_template `else` arm before it gets byte-order-prefixed as f'{endian}{struct_fmt}') -- so the minus sign is always there, but a prefix in front of it defeats a plain '^-\d+' anchor (caught by #827's cross-review: NumberField(length=-1) produced '>-1s', misdiagnosed as malformed). FieldBase.length checks the pattern once struct.calcsize has failed, and raises a distinct, template-naming ProtocolError for anything else calcsize cannot size. Both branches still chain from the real struct.error via `from error`, so no bare struct.error escapes either way, and the negative-length message and __cause__ chain are byte-for-byte unchanged for the existing (unprefixed) case -- so the pinned message assertion at tests/protocols/application/test_http_unit.py:662 needs no change. - tests/corekit/test_fields_field.py: three new tests on FieldBaseLengthNegativeResolvedLengthTests -- a malformed template raises ProtocolError naming the template and not claiming a negative length; neither category ever leaks a bare struct.error; and a real NumberField(length=-1), whose template comes out byte-order-prefixed ('>-1s'), is still reported as negative, not malformed. All three fail on stock/pre-fix code with the wrong diagnosis and pass after. #825 also asks whether the negative length should be prevented, not just correctly reported, by bounding pkt['__length__'] at the schema layer. Measured directly (both a global clamp in schema.py's decrement and a narrow max(pkt['__length__'], 0) on GoawayFrame.debug / ContinuationFrame.fragment, matching the existing sctp.py/pcapng.py convention): the GOAWAY repro still raises ProtocolError either way, just a different one ("HTTP/2: [Type 7] invalid format" from httpv2.py's own schema.length > length guard, __cause__ None) that breaks the pinned assertion in three ways, not just its message -- so the one relaxation this change is allowed would not save it. Left for its own change with the schema.py owner's input; not attempted here. Build: mypy and isort (-l100 -ppcapkit) clean on the changed source file. tests/corekit/test_fields_field.py's affected test class (5/5) and the application-side pinned scenario verified directly; full tests/corekit and tests/protocols/application suites re-run.
2bd98bf to
298daa2
Compare
|
Nothing on this PR needs your decision. The
What is actually waiting on you is merging. Three PRs are green and cleared:
One genuine design question I deferred rather than decided, if you want to settle it now — otherwise it stays in #825 for its own PR. #825 has two halves. The first (a malformed template misreported as a negative length) is fixed in #827. The second is that a negative Bounding it at the schema layer is the obvious fix, and both ways of doing it were measured: the GOAWAY then raises |
|
Fixed at So the endian-prefixed negatives are classified correctly, no control moved, and The comment was corrected on both counts too: it now says the byte-order prefix precedes the minus and so defeats the The new test uses the real
|
|
Coverage is now confirmed, closing the one
86% → 87% with the missed count flat at 12, corroborated by test counts moving 220 → 222 — the two new tests and nothing else. The reviewer's addendum restates Three measurement traps it recorded, worth having on the record because each produced a confident wrong number before it caught them:
|
…in FieldBase.length (#825) struct.calcsize raises the identical bare struct.error for a malformed template as for a negative resolved count (measured on 3.14.7: calcsize('-1s') and calcsize('Xs') both raise "bad char in struct format"). #811's guard caught that blanket and always reported "resolved to a negative length", misdiagnosing a typo'd template. - pcapkit/corekit/fields/field.py: add _RE_NEGATIVE_LENGTH_TEMPLATE, matching a negative resolved count's leading '-', optionally preceded by one of NumberField's byte-order prefixes ('@=<>!'). Every template built from a resolved length is f'{length}s' (strings.py, misc.py, collections.py, and numbers.py's build_template `else` arm before it gets byte-order-prefixed as f'{endian}{struct_fmt}') -- so the minus sign is always there, but a prefix in front of it defeats a plain '^-\d+' anchor (caught by #827's cross-review: NumberField(length=-1) produced '>-1s', misdiagnosed as malformed). FieldBase.length checks the pattern once struct.calcsize has failed, and raises a distinct, template-naming ProtocolError for anything else calcsize cannot size. Both branches still chain from the real struct.error via `from error`, so no bare struct.error escapes either way, and the negative-length message and __cause__ chain are byte-for-byte unchanged for the existing (unprefixed) case -- so the pinned message assertion at tests/protocols/application/test_http_unit.py:662 needs no change. - tests/corekit/test_fields_field.py: three new tests on FieldBaseLengthNegativeResolvedLengthTests -- a malformed template raises ProtocolError naming the template and not claiming a negative length; neither category ever leaks a bare struct.error; and a real NumberField(length=-1), whose template comes out byte-order-prefixed ('>-1s'), is still reported as negative, not malformed. All three fail on stock/pre-fix code with the wrong diagnosis and pass after. #825 also asks whether the negative length should be prevented, not just correctly reported, by bounding pkt['__length__'] at the schema layer. Measured directly (both a global clamp in schema.py's decrement and a narrow max(pkt['__length__'], 0) on GoawayFrame.debug / ContinuationFrame.fragment, matching the existing sctp.py/pcapng.py convention): the GOAWAY repro still raises ProtocolError either way, just a different one ("HTTP/2: [Type 7] invalid format" from httpv2.py's own schema.length > length guard, __cause__ None) that breaks the pinned assertion in three ways, not just its message -- so the one relaxation this change is allowed would not save it. Left for its own change with the schema.py owner's input; not attempted here. Build: mypy and isort (-l100 -ppcapkit) clean on the changed source file. tests/corekit/test_fields_field.py's affected test class (5/5) and the application-side pinned scenario verified directly; full tests/corekit and tests/protocols/application suites re-run.
298daa2 to
d3ae174
Compare
|
Delta re-review verdict: GOOD TO GO (haiku, same reviewer, on I owe this comment — the verdict came in and I reported it in the session but never posted it here, so this PR has been reading Its 28-template matrix had 0 mismatches, and its attacks on the widened pattern were all correctly refused: Two nuances it recorded, both of which I verified: Coverage confirmed 86% → 87%, misses flat at 12, corroborated by 220 → 222 tests. |
make pylint,make mypy,make isort)make testpasses, and a test case covers the changeWhat is the purpose of your pull request?
fix— corrects a defectDescription
struct.calcsizeraises the identical barestruct.errorfor a malformedtemplate as for a negative resolved count (
calcsize('-1s')andcalcsize('Xs')both raise "bad char in struct format"). #811's guardcaught that blanket and always reported "resolved to a negative length",
misdiagnosing a typo'd template as the wrong category of error.
FieldBase.lengthnow tells the two apart oncestruct.calcsizehasfailed, using a pattern match against the template itself (every template
this package builds is
f'{length}s'; a negative count is the only wayone starts with
-). Both branches still chain from the realstruct.error, so neither leaks a bare one, and the negative-lengthmessage and
__cause__are unchanged for the existing case.Also measured (not fixed here): whether the negative length should be
prevented rather than just correctly reported. Both a global clamp in
schema.py's decrementing and a narrow one on the two affected fieldsstill leave the GOAWAY repro raising a different
ProtocolError("invalid format", from
httpv2.py's own length guard) — so it needs itsown change, not a hasty one here.
Closes #825