Skip to content

@prepare raises a bare EOFError for any zero-length schema, so an empty nested area cannot unpack #458

Description

@JarryShaw

@prepare treats a zero-length schema as end-of-file, so any schema whose fields sum to zero octets — or any nested schema handed an empty area — raises EOFError instead of unpacking to an empty instance.

Mechanism

pcapkit/utilities/decorators.py:221-222:

if length == 0:
    raise EOFError

That is unconditional. It is a reasonable guard for the frame reader, where a zero-length read genuinely means the capture is exhausted, but @prepare wraps Schema.unpack, which is also called for nested schemas and for schemas that legitimately have nothing to read.

Reproduction, on e2d8ed6d1

@schema_final
class Empty(Schema):
    pass

Empty.unpack(b'', 0, {})
EOFError: EOFError()

A bare EOFError with no message, from a decorator the caller never mentioned.

Why this was unreachable until now

It is guarded behind the nested-packet fault in #445: before that is fixed, a nested schema sized from an enclosing field dies with KeyError: 'length' long before a zero-length area can be handed to unpack. PR #457 fixes #445, and five HTTP/2 frame schemas then reach this instead — so it becomes live the moment #457 lands.

Fix

Distinguish "the stream is exhausted" from "this schema has nothing to read". The frame-reader case needs the EOFError; the schema case wants an empty instance. Options, in rough order of invasiveness:

  • Raise only when the underlying stream is genuinely at EOF (data.read(0) semantics differ from a declared length == 0), rather than on the declared length.
  • Let Schema.unpack accept length == 0 and return an instance with empty buffers, and keep the EOFError in whichever caller actually needs it.
  • Give @prepare a flag for the nested case, which is the least attractive since it pushes the distinction onto every call site.

House convention would also prefer an in-library exception from pcapkit.utilities.exceptions over a bare EOFError wherever this does stay fatal, since a caller currently cannot tell this apart from a truncated capture.

Provenance

Surfaced by the agent implementing #445 (PR #457), which found that fixing the KeyError unblocks six HTTP/2 frame schemas whose pack-side flags lookup was previously unreachable — two now round-trip and five reach this and other latent defects. Verified and reproduced independently before filing.

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

    bugIssues reporting a defect (set by the bug report template; a default, not an assessment)

    Projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions