Validate nanoseconds range when unpacking timestamps in the C extension#716
Open
chuenchen309 wants to merge 1 commit into
Open
Validate nanoseconds range when unpacking timestamps in the C extension#716chuenchen309 wants to merge 1 commit into
chuenchen309 wants to merge 1 commit into
Conversation
unpack_timestamp() decoded the nanoseconds field of a timestamp64/96 but never range-checked it, so with timestamp=1|2|3 the C extension silently accepted a malformed value >= 1e9, while the pure-Python fallback and the C extension's own timestamp=0 path both reject it. The MessagePack spec states nanoseconds must not be larger than 999999999. Add the range check in unpack_timestamp() so all modes reject consistently. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR fixes a correctness gap in the C extension’s timestamp unpacking by validating that the decoded nanoseconds field is within the MessagePack timestamp spec range, ensuring consistent behavior across all timestamp= modes and matching the pure-Python fallback.
Changes:
- Add a nanoseconds upper-bound check (
<= 999,999,999) in the C extension’sunpack_timestamp()fast path. - Add a regression test asserting out-of-range nanoseconds are rejected for
timestamp=0/1/2/3.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
msgpack/unpack.h |
Adds nanoseconds range validation in unpack_timestamp() so malformed timestamp64/96 payloads error consistently across modes. |
test/test_timestamp.py |
Adds a regression test ensuring out-of-range nanoseconds are rejected for all timestamp= modes. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| return -1; | ||
| } | ||
| if (ts->tv_nsec > 999999999) { | ||
| PyErr_Format(PyExc_ValueError, "nanoseconds must be a non-negative integer less than 999999999."); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The C extension's
unpack_timestamp()decodes the nanoseconds field of a timestamp64/timestamp96 but never range-checks it, so withtimestamp=1|2|3it silently accepts a malformed value ≥ 1,000,000,000:Three signals agree this is a bug, not lenient parsing:
Timestamp.__init__) already rejects it in every mode.timestamp=0(which routes throughTimestamp); only the1/2/3fast paths skip validation.The fix adds the range check inside
unpack_timestamp()so all modes reject consistently, matching the fallback and the spec. Valid nanoseconds (≤ 999999999) are unaffected. Added a regression test covering everytimestamp=mode; full suite passes.Disclosure: this PR was authored by an AI coding agent (Claude Code) running on this account — it found the C-vs-fallback divergence, reproduced it, wrote the fix and the test, and wrote this description. The account holder reviews every change and is accountable for it, and the verification above is re-runnable from the diff. Happy to close it if it isn't the kind of contribution you want.