fix(mql): terminate parse loop on quoted value as final token - #222
Conversation
|
Warning Review limit reached
Next review available in: 56 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe quoted-value scanner loop now detects EOF without progress, preventing an infinite loop when a quoted value is the final token. A regression test covers multiple final-token inputs and validates the parsed expression. ChangesQuoted Value EOF Handling
Estimated code review effort: 2 (Simple) | ~10 minutes Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
0d97391 to
45deaa2
Compare
Parser.Parse looped forever on inputs like k:"v" where a quoted value is the final token. In parseValueFromPos the scanner-advance loop advances until the offset passes the closing quote, but when the quote is the last character the scanner is already at EOF and next() no longer advances the offset, so the loop condition stays true indefinitely. Guard the loop on forward progress: break when next() fails to advance the scanner offset. Add a regression test asserting termination via a timeout. Fixes #221 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
45deaa2 to
e53ad2b
Compare
Summary
mql.NewParser(...).Parse()loops forever on any query where a quoted value is the final token, e.g.k:"v"orname:"alice". This is a denial-of-service hazard for any code that parses untrusted MQL input on a request path.Fixes #221.
Root cause
In
mql/parser.go,parseValueFromPosadvances the scanner past a quoted string with:When the closing quote is the last character of the input,
endIdx+1 == len(input). The scanner is already at EOF, sonext()no longer advancesOffset(it caps at the input length). The conditionlen(input)-1 < len(input)stays true forever, and the loop never terminates.Non-final quoted values happen to work only because later tokens push
Offsetpast the threshold, letting the loop exit.Fix
Guard the loop on forward progress — break as soon as
next()fails to advance the scanner offset (i.e. EOF):Compatibility — not a breaking change
This is a strict bug fix; no exported API, signature, or type changes.
breakis unreachable for any input that already terminated. It fires only whennext()fails to advance the scanner offset, whichtext/scannerdoes only at EOF. Any previously-terminating input satisfied the original exit condition (Offset-1 < endIdx+1going false) before reaching EOF, so the added branch is never taken and the returned value and final scanner position are identical.TermExpr.k:"unclosed) never enters this block (endIdx == len(input)) and still falls through to the unquoted-value path unchanged.A differential battery over quoted/unquoted/dotted-key/compound/unclosed-quote/wildcard inputs produced identical results to the pre-fix parser on every input that didn't hang.
Test
Adds
TestParseQuotedValueAsFinalTokenin a newmql/parser_test.go. Each case parses in a goroutine and asserts termination within a timeout, so a future regression fails the suite instead of hanging it. It also asserts the parsed key/value are correct. The test hangs (times out) against the old code and passes against the fix.🤖 Generated with Claude Code
Summary by CodeRabbit
Bug Fixes
Tests