Skip to content

GROOVY-12272: Validate JSON string escapes where they are read - #2809

Open
paulk-asert wants to merge 1 commit into
apache:masterfrom
paulk-asert:groovy12272
Open

GROOVY-12272: Validate JSON string escapes where they are read#2809
paulk-asert wants to merge 1 commit into
apache:masterfrom
paulk-asert:groovy12272

Conversation

@paulk-asert

Copy link
Copy Markdown
Contributor

JsonLexer's string branch appended one character at a time and, at every unescaped quote, re-validated the whole accumulated token by copying it to a String and running two regular expressions over it. For a well formed string the closing quote is the first unescaped one, so that happened once. For a string holding an invalid escape the validation could never succeed, so the loop consumed the rest of the document and paid the cost again at every quote it passed, giving O(n^2) behaviour on input an author controls.

Measured on a document of the shape {"k":"\q" followed by n quotes, parsed with JsonSlurperClassic:

quotes before after
2,000 42 ms 4 ms
4,000 67 ms 0 ms
8,000 220 ms 0 ms
16,000 874 ms 0 ms

Read and check each escape sequence where the backslash is found instead. The scan becomes linear, the accepted language is unchanged, and a bad escape is now reported at its own position rather than after the document has been consumed to its end. Escape-state tracking is no longer needed, since consuming the sequence in place is what distinguishes an escaped quote from a closing one.

Note the reach is wider than the parser: JsonOutput.prettyPrint(String) lexes through the same class, so it shared the behaviour.

JsonLexer's string branch appended one character at a time and, at every
unescaped quote, re-validated the whole accumulated token by copying it to
a String and running two regular expressions over it. For a well formed
string the closing quote is the first unescaped one, so that happened once.
For a string holding an invalid escape the validation could never succeed,
so the loop consumed the rest of the document and paid the cost again at
every quote it passed, giving O(n^2) behaviour on input an author controls.

Measured on a document of the shape {"k":"\q" followed by n quotes, parsed
with JsonSlurperClassic:

  quotes    before     after
   2,000     42 ms      4 ms
   4,000     67 ms      0 ms
   8,000    220 ms      0 ms
  16,000    874 ms      0 ms

Read and check each escape sequence where the backslash is found instead.
The scan becomes linear, the accepted language is unchanged, and a bad
escape is now reported at its own position rather than after the document
has been consumed to its end. Escape-state tracking is no longer needed,
since consuming the sequence in place is what distinguishes an escaped
quote from a closing one.

Note the reach is wider than the parser: JsonOutput.prettyPrint(String)
lexes through the same class, so it shared the behaviour.
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.77778% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.1755%. Comparing base (5f56279) to head (db9e70b).
⚠️ Report is 4 commits behind head on master.

Files with missing lines Patch % Lines
...oovy-json/src/main/java/groovy/json/JsonLexer.java 77.7778% 2 Missing and 2 partials ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               master      #2809        +/-   ##
==================================================
+ Coverage     70.1516%   70.1755%   +0.0239%     
- Complexity      35828      35845        +17     
==================================================
  Files            1562       1562                
  Lines          132523     132542        +19     
  Branches        24379      24384         +5     
==================================================
+ Hits            92967      93012        +45     
+ Misses          31140      31114        -26     
  Partials         8416       8416                
Files with missing lines Coverage Δ
...oovy-json/src/main/java/groovy/json/JsonLexer.java 80.5556% <77.7778%> (-2.4232%) ⬇️

... and 9 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

testlens-app Bot commented Aug 18, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: db9e70b
▶️ Tests: 110470 executed
⚪️ Checks: 31/31 completed


Learn more about TestLens at testlens.app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants