Repository navigation
[LOW] Prevent parser stack and cache exhaustion - #109
Closed
OskarEichler wants to merge 1 commit into
Closed
OskarEichler wants to merge 1 commit into
OskarEichler wants to merge 1 commit into
Conversation
jaynetics
added a commit
that referenced
this pull request
Sep 19, 2026
- use queues or frames instead of recursion to prevent SystemStackError, closes #109 - extract static, re-usable scanner data into Scanner constants instead of writing it for every scan - various minor performance tweaks - improve scanner error messages by slicing only up to the offending character - add benchmarks for traversal and comparison methods
jaynetics
added a commit
that referenced
this pull request
Sep 19, 2026
- use queues or frames instead of recursion to prevent SystemStackError, closes #109 - extract static, re-usable scanner data into Scanner constants instead of writing it for every scan - various minor performance tweaks - improve scanner error messages by slicing only up to the offending character - add benchmarks for traversal and comparison methods
jaynetics
added a commit
that referenced
this pull request
Sep 19, 2026
- use queues or frames instead of recursion to prevent SystemStackError, closes #109 - extract static, re-usable scanner data into Scanner constants instead of writing it for every scan - various minor performance tweaks - improve scanner error messages by slicing only up to the offending character - add benchmarks for traversal and comparison methods
jaynetics
added a commit
that referenced
this pull request
Sep 19, 2026
- use queues or frames instead of recursion to prevent SystemStackError, closes #109 - extract static, re-usable scanner data into Scanner constants instead of writing it for every scan - various minor performance tweaks - improve scanner error messages by slicing only up to the offending character - add benchmarks for traversal and comparison methods
Collaborator
|
@OskarEichler thank you very much for pointing out this issue! I have worked around it in #110 together with some other improvements. The approach is similar to yours, but a bit more fine-tuned to the individual use cases of the various code paths, so as to avoid a negative impact on performance. |
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.
Summary
Security impact
Severity: LOW. Applications that parse attacker-influenced regular-expression text can be forced to raise
SystemStackErrorwith roughly 4,000 nested groups. Unlike ordinary parser errors,SystemStackErrorbypasses commonrescue StandardErrorboundaries and can terminate the worker handling the input.Applications that also expose the optional syntax-version argument can be made to retain every unique valid version alias for the process lifetime. Ten thousand supplied aliases create 10,001 cache entries; the cache has no eviction or bound.
The impact is availability only and requires an application to pass attacker-influenced patterns or syntax aliases into Regexp Parser. Songstats receives the gem through development RuboCop and does not expose either input.
Reproduction and fix
On 2.12.0 and current
master, nested passive or capture groups raiseSystemStackErrorat approximately 4,000 levels on Ruby 4.0.6. This branch parses and traverses 16,000 levels in bounded models by using explicit work stacks. Capture-heavy parsing is kept linear by tracking the already-computed total directly.Calling
Regexp::Syntax.forwith 10,000 uniqueruby/999.x.0aliases retains all 10,000 caller strings on the baseline. The returned value is already a class singleton, so removing the alias cache preserves resolution while eliminating retained input.Verification
SystemStackErrorat 4,000git diff --checkpassNo repository tests were added or changed.
Compatibility and limitations
Breaking changes: none expected. AST traversal order, traversal events, child indices, nesting levels, capture numbering, syntax fallback, and returned syntax classes are unchanged. Code that introspects the undocumented
Regexp::Syntax@alias_mapinstance variable will no longer find it.Memory and CPU still grow with input size; this patch removes the avoidable stack failure, quadratic capture counting, and permanent alias retention rather than turning the parser into a resource sandbox. Other recursive opt-in operations on a returned AST, such as rendering very deeply nested trees, are outside this patch.