Skip to content

The signed seven-byte bound rounds upward before BigInt conversion, causing consumeBigIntegral to consume eight bytes #912

Description

@MicroMilo

Summary

consumeBigIntegral(7, true) violates its maximum-byte contract. The signed maximum is calculated as BigInt(2 ** 55 - 1), but the intermediate Number rounds to 2 ** 55. The resulting inclusive range requires eight bytes. On the minimized eight-byte input 0000000000000001, the method consumes all eight bytes despite a maximum of seven and returns 36028797018963968.

Validation source commit: 4c14e1bf63d82475ea057d6208e6f2eac87fa680.

Code path

  • packages/core/FuzzedDataProvider.ts:107-116: Public consumeBigIntegral byte-limit contract and method entry
  • packages/core/FuzzedDataProvider.ts:605-618: Signed bound calculation converts an already-rounded Number to BigInt
  • packages/core/FuzzedDataProvider.ts:634-656: Range loop consumes one byte for every eight bits in the erroneous inclusive range
  • packages/core/core.ts:474-476: Public package export of FuzzedDataProvider
  • Repository-local validation artifact: Executable minimized witness

Steps to reproduce

This report is based on a source-control-flow validation against the commit above.

  1. Check out the source commit listed in this report.
  2. Inspect the code path and contract anchors listed above.
  3. Exercise the described boundary/state path: The signed seven-byte bound rounds upward before BigInt conversion, causing consumeBigIntegral to consume eight bytes.
  4. Compare the observed behavior with the expected contract below.

Validation note: It deterministically reports requestedMaximumBytes=7, inputHex=0000000000000001, expectedRemainingBytes=1, actualRemainingBytes=0, signedMaximum=36028797018963967, actualValue=36028797018963968, and violationObserved=true.

Expected behavior

The implementation should preserve the repository contract described by the documentation, public type, parser, serializer, or sibling implementation anchors above.

Actual behavior

consumeBigIntegral(7, true) violates its maximum-byte contract. The signed maximum is calculated as BigInt(2 ** 55 - 1), but the intermediate Number rounds to 2 ** 55. The resulting inclusive range requires eight bytes. On the minimized eight-byte input 0000000000000001, the method consumes all eight bytes despite a maximum of seven and returns 36028797018963968.

Existing coverage

Suggested fix

Compute consumeBigIntegral signed bounds without Number rounding so the range reader respects maxNumBytesToConsume.

Suggested tests

  • Add a regression test for: The signed seven-byte bound rounds upward before BigInt conversion, causing consumeBigIntegral to consume eight bytes.
  • Include the boundary value or state transition described above so the old behavior fails before the fix.

Submitted with Codex.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions