Skip to content

NumberField with a callable length cannot pack at 8 octets: _need_process latches True from the placeholder and is never cleared #591

Description

@JarryShaw

A NumberField whose length is a callable is unpackable once that callable resolves to 8 octets: _need_process is latched True while the field is still a placeholder and is never cleared when the real length arrives, so pre_process returns bytes to a struct template that now expects an integer.

Mechanism

numbers.py:109 sets the flag false in __init__, and the template builder sets it true for any length that is not 8, 4, 2 or 1:

else:                 # do not unpack
    struct_fmt = f'{length}s'
    self._need_process = True

A callable length is a placeholder of -1 at construction, which takes that branch. When __call__ later resolves the real width the template is rebuilt correctly — but nothing resets _need_process. So pre_process at numbers.py:194 takes the process path, self._length is now 8 rather than negative so the _length < 0 repair at :196-203 is skipped, and :205 returns

return value.to_bytes(self._length, self._byteorder, signed=self._signed)

bytes, into a template that is by then >Q.

Measured

Executed on origin/main (9c240a60e), CPython 3.14.7. The comparison is the proof — identical resolved length and identical template, differing only in how the length was supplied:

--- callable length (resolves to 8) ---
length= 8  _need_process= True   template= >Q
  error: required argument is not an integer

--- static length 8, for comparison ---
length= 8  _need_process= False  template= >Q
pack -> 0000010000000000

So NumberField(length=lambda pkt: 8) cannot pack, while NumberField(length=8) packs the same value through the same template.

Impact on the wire

This makes every extended (8-octet) MPTCP DSS form unpackable, since those widths are selected at runtime from the DSS flags and therefore must come from a callable. Reported as:

_make_mptcp_dss(DSS, ack=1 << 40)  ->  struct.error: required argument is not an integer

Any other schema that resolves a numeric width to 8 octets through a callable has the same failure.

Notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions