Two related defects in #811's negative-length guard, both surfaced by #823's cross-review and both confirmed here.
1. The message is a category error. FieldBase.length (pcapkit/corekit/fields/field.py:284-290) catches struct.error blanket and unconditionally reports f'Field {self.name} resolved to a negative length; template={self.template!r}'. But struct.calcsize raises the same error for a malformed template as for a negative count — measured on 3.14.7:
calcsize('-1s') -> struct.error: bad char in struct format
calcsize('Xs') -> struct.error: bad char in struct format
So a schema with a typo'd template is reported as a negative length, which sends the reader to the wrong cause. The guard should distinguish the two — the negative case is detectable from the resolved length before calcsize is called at all.
2. The negative length is reported, never prevented. A SchemaWarning: packet length < 0: -1 fires before the ProtocolError, so pkt['__length__'] still goes negative and the schema still builds a '-1s' template; #811 converts the resulting exception rather than stopping the arithmetic. #823's reviewer found 32 inputs across two different fields (debug and fragment) taking this path in a 1210-case sweep, so it is a class of input, not one packet. The real fix bounds pkt['__length__'] at the schema layer.
Related and worth re-measuring in the same change: http.py:318-319 (except (ValueError, struct.error) in the preface arm) took zero hits across that 1210-case sweep and may now be unreachable, and http.py:416's contextlib.suppress(ProtocolError, struct.error) is likely in the same position. Neither is safe to simply delete — StructError subclasses struct.error, and the comment at :401-402 explains why removing a suppression from a non-final arm previously caused an HTTP/1→HTTP/2 mislabel.
Note the test pinned by #823 asserts the current message verbatim, so fixing (1) will red it; assertIn('negative length', …) there would survive.
Two related defects in #811's negative-length guard, both surfaced by #823's cross-review and both confirmed here.
1. The message is a category error.
FieldBase.length(pcapkit/corekit/fields/field.py:284-290) catchesstruct.errorblanket and unconditionally reportsf'Field {self.name} resolved to a negative length; template={self.template!r}'. Butstruct.calcsizeraises the same error for a malformed template as for a negative count — measured on 3.14.7:So a schema with a typo'd template is reported as a negative length, which sends the reader to the wrong cause. The guard should distinguish the two — the negative case is detectable from the resolved length before
calcsizeis called at all.2. The negative length is reported, never prevented. A
SchemaWarning: packet length < 0: -1fires before theProtocolError, sopkt['__length__']still goes negative and the schema still builds a'-1s'template; #811 converts the resulting exception rather than stopping the arithmetic. #823's reviewer found 32 inputs across two different fields (debugandfragment) taking this path in a 1210-case sweep, so it is a class of input, not one packet. The real fix boundspkt['__length__']at the schema layer.Related and worth re-measuring in the same change:
http.py:318-319(except (ValueError, struct.error)in the preface arm) took zero hits across that 1210-case sweep and may now be unreachable, andhttp.py:416'scontextlib.suppress(ProtocolError, struct.error)is likely in the same position. Neither is safe to simply delete —StructErrorsubclassesstruct.error, and the comment at:401-402explains why removing a suppression from a non-final arm previously caused an HTTP/1→HTTP/2 mislabel.Note the test pinned by #823 asserts the current message verbatim, so fixing (1) will red it;
assertIn('negative length', …)there would survive.