Don't throw BoundsError when reporting UnexpectedEOF - #477
Merged
Conversation
`_invalid` computed the error's line number with `view(cus, 1:pos)`
without clamping `pos` to the buffer, while the snippet slice two lines
below already clamped with `min(sizeof(cus), pos + 20)`. UnexpectedEOF is
reported at the byte the parser wanted to read, so every input ending
mid-token arrives with `pos == sizeof(cus) + 1` and the error path itself
threw BoundsError instead of the intended ArgumentError.
Affected every truncated input, including `JSON.parse("{")`,
`JSON.parse("[1")`, `JSON.parse("\"a")` and whitespace-only buffers
like " " and "\n"; it reached typed, lazy and byte-buffer entry points
alike. Callers that catch ArgumentError to report malformed input saw an
unrelated BoundsError escape instead.
Clamp the line-count range and the snippet's left index. The message is
otherwise unchanged: position, line number, snippet and caret still point
at the truncation, e.g. parsing "{\n \"a\": 1,\n \"b\":" reports
byte position 19 on line 3.
Found while fuzzing tool-argument parsing in a downstream agent framework,
where a truncated LLM-produced arguments string surfaced as BoundsError.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #477 +/- ##
=======================================
Coverage 89.98% 89.99%
=======================================
Files 7 7
Lines 1518 1519 +1
=======================================
+ Hits 1366 1367 +1
Misses 152 152 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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 bug
Any JSON input that ends mid-token throws
BoundsErrorfrom inside the error-reporting path, instead of theArgumentErrorthe parser means to raise:Same for
JSON.parse("["),JSON.parse("[1"),JSON.parse("\"a"),JSON.parse("{\"a\":"), and whitespace-only buffers such as" "and"\n". It reaches the typed, lazy and byte-buffer entry points alike (JSON.parse(str, T),JSON.lazy(str)[],JSON.parse(Vector{UInt8}(...))).Cause
_invalidcomputes the error's line number aswithout clamping
posto the buffer, while the snippet slice two lines below already clamps (ri = min(sizeof(cus), pos + 20)).UnexpectedEOFis reported at the byte the parser wanted to read, so truncated input always arrives here withpos == sizeof(cus) + 1and theviewis out of bounds.Inputs that stop exactly at the last byte (e.g.
JSON.parse("{\"cmd\":\"echo hi\\")) reportpos == sizeof(cus)and correctly raiseArgumentError, which is why this went unnoticed — the existing incomplete-escape test intest/parse.jltakes that path.Fix
Clamp the line-count range, and the snippet's left index for good measure. The message is otherwise unchanged — position, line number, snippet and caret still point at the truncation:
Tests
New
@testset "truncated input reports UnexpectedEOF"intest/parse.jlcovering 13 truncation shapes across the string, typed, lazy and byte-buffer entry points, plus assertions that the message still carries the right byte position, line number and<EOF>marker. Verified these fail on unfixed code (allBoundsError) and pass with the fix. Full suite green viaPkg.test().How it turned up
Fuzzing tool-argument parsing in a downstream agent framework: a truncated LLM-produced arguments string surfaced as
BoundsErrorrather than theArgumentErrorthe caller catches to report malformed input.