Skip to content

GROOVY-12275: Encode snippet attribute values and bound snippet marku… - #2812

Merged
paulk-asert merged 1 commit into
apache:masterfrom
paulk-asert:groovy12275
Aug 18, 2026
Merged

GROOVY-12275: Encode snippet attribute values and bound snippet marku…#2812
paulk-asert merged 1 commit into
apache:masterfrom
paulk-asert:groovy12275

Conversation

@paulk-asert

Copy link
Copy Markdown
Contributor

…p regexes

Two defects in the same {@snippet} handling, both reached from a doc comment in the source being documented.

The class and id attributes were appended to the generated element without encoding. The attribute parser accepts a double quote inside a value which was single quoted or unquoted, so a value could close its attribute and the tag around it. Encode both through a new SimpleGroovyClassDoc.encodeAttribute, which escapes the ampersand first and then the characters that can end an attribute or start a tag. The snippet body was already escaped; this brings the attributes up to the same standard.

A markup directive's regex attribute was compiled and run against snippet lines with no bound. Give each directive a deadline using RegexGuard, and leave the line unannotated rather than half annotated if it expires.

The payload in the test is worth a note. The finding cites (a+)+$ against a long run of characters, and on a current JDK that is not slow: the textbook nested-quantifier patterns, (a+)+b, (a|aa)+$, (x+x+)+y and (a*)*b among them, all complete in about a millisecond, because the engine recognises them. A backreference still backtracks exponentially. Measured with the guard removed, a directive carrying (a+)+\1b against a 32 character line took 152 seconds to render one page, and grows exponentially with the line; with the guard the same page renders in well under a second. So the finding is right that the risk exists and wrong about how it is reached, and a test built on its own example would have passed with or without a fix.

…p regexes

Two defects in the same {@snippet} handling, both reached from a doc comment
in the source being documented.

The class and id attributes were appended to the generated element without
encoding. The attribute parser accepts a double quote inside a value which
was single quoted or unquoted, so a value could close its attribute and the
tag around it. Encode both through a new SimpleGroovyClassDoc.encodeAttribute,
which escapes the ampersand first and then the characters that can end an
attribute or start a tag. The snippet body was already escaped; this brings
the attributes up to the same standard.

A markup directive's regex attribute was compiled and run against snippet
lines with no bound. Give each directive a deadline using RegexGuard, and
leave the line unannotated rather than half annotated if it expires.

The payload in the test is worth a note. The finding cites (a+)+$ against a
long run of characters, and on a current JDK that is not slow: the textbook
nested-quantifier patterns, (a+)+b, (a|aa)+$, (x+x+)+y and (a*)*b among
them, all complete in about a millisecond, because the engine recognises
them. A backreference still backtracks exponentially. Measured with the
guard removed, a directive carrying (a+)+\1b against a 32 character line
took 152 seconds to render one page, and grows exponentially with the line;
with the guard the same page renders in well under a second. So the finding
is right that the risk exists and wrong about how it is reached, and a test
built on its own example would have passed with or without a fix.
@paulk-asert
paulk-asert merged commit 55dcfb9 into apache:master Aug 18, 2026
28 of 29 checks passed
@paulk-asert
paulk-asert deleted the groovy12275 branch August 18, 2026 10:37
@codecov-commenter

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.60870% with 4 lines in your changes missing coverage. Please review.
✅ Project coverage is 70.1876%. Comparing base (f140841) to head (0a0bf52).
⚠️ Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...g/codehaus/groovy/tools/groovydoc/TagRenderer.java 82.3529% 2 Missing and 1 partial ⚠️
...s/groovy/tools/groovydoc/SimpleGroovyClassDoc.java 83.3333% 0 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##               master      #2812        +/-   ##
==================================================
+ Coverage     70.1837%   70.1876%   +0.0039%     
- Complexity      35844      35849         +5     
==================================================
  Files            1562       1562                
  Lines          132528     132542        +14     
  Branches        24379      24379                
==================================================
+ Hits            93013      93028        +15     
- Misses          31106      31107         +1     
+ Partials         8409       8407         -2     
Files with missing lines Coverage Δ
...s/groovy/tools/groovydoc/SimpleGroovyClassDoc.java 83.3977% <83.3333%> (-0.0008%) ⬇️
...g/codehaus/groovy/tools/groovydoc/TagRenderer.java 71.5832% <82.3529%> (+0.4478%) ⬆️

... and 6 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.

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.

2 participants