[
https://issues.apache.org/jira/browse/GROOVY-12687?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18137824#comment-18137824
]
ASF GitHub Bot commented on GROOVY-12687:
-----------------------------------------
paulk-asert merged PR #3206:
URL: https://github.com/apache/groovy/pull/3206
> groovyc: StackOverflowError when the error tolerance is reached inside a
> type-checking extension
> ------------------------------------------------------------------------------------------------
>
> Key: GROOVY-12687
> URL: https://issues.apache.org/jira/browse/GROOVY-12687
> Project: Groovy
> Issue Type: Bug
> Affects Versions: 6.0.0
> Reporter: Scott Murphy Heiberg
> Priority: Major
>
> When a type-checking extension reports the error that reaches the compiler's
> error tolerance (10 by default), {{groovyc}} (with or without {{--check}})
> prints no diagnostics and ends with a {{StackOverflowError}}. Ten reports
> from NullChecker in one method are enough.
> {{TenOnly.groovy}}:
> {code:groovy}
> import groovy.transform.TypeChecked
> @interface Nullable {}
> @TypeChecked(extensions = 'groovy.typecheckers.NullChecker')
> class TenOnly {
> void touch(@Nullable String a) {
> a.length(); a.length(); a.length(); a.length(); a.length()
> a.length(); a.length(); a.length(); a.length(); a.length()
> }
> }
> {code}
> {code:sh}
> groovyc --check --error-format=short TenOnly.groovy
> {code}
> Actual: exit 1 and about 1,000 lines on stderr, no diagnostic:
> {code:text}
> java.lang.reflect.InvocationTargetException
> at
> org.codehaus.groovy.tools.GroovyStarter.rootLoader(GroovyStarter.java:150)
> at org.codehaus.groovy.tools.GroovyStarter.main(GroovyStarter.java:52)
> Caused by: java.lang.StackOverflowError
> ...
> at
> org.codehaus.groovy.control.ErrorFormat.writeShort(ErrorFormat.java:116)
> at org.codehaus.groovy.control.ErrorFormat$2.write(ErrorFormat.java:71)
> at
> org.codehaus.groovy.control.ErrorCollector.write(ErrorCollector.java:349)
> at
> org.codehaus.groovy.control.MultipleCompilationErrorsException.getMessage(MultipleCompilationErrorsException.java:79)
> at
> org.codehaus.groovy.control.messages.ExceptionMessage.toDiagnostic(ExceptionMessage.java:68)
> at
> org.codehaus.groovy.control.ErrorFormat.writeShort(ErrorFormat.java:116)
> (the last five frames repeat; 203 times in the printed trace)
> {code}
> The same file without {{--error-format=short}} cycles through
> {{ErrorFormat.writeFull}}, {{ExceptionMessage.write}} and the same
> {{ErrorCollector.write}} / {{MultipleCompilationErrorsException.getMessage}}
> pair. Neither {{--check}} nor the annotation is required: the same class with
> eleven dereferences and no {{@TypeChecked}}, compiled with {{groovyc -d out
> --configscript nullchecker.groovy Many.groovy}} where {{nullchecker.groovy}}
> is {{withConfig(configuration) { ast(groovy.transform.TypeChecked,
> extensions: ['groovy.typecheckers.NullChecker']) } }}, fails the same way.
> Expected: the ten diagnostics and {{10 errors}}, as for ordinary type errors.
> Controls:
> * The same class with nine dereferences prints nine {{Potential null
> dereference: 'a' is @Nullable}} lines and {{9 errors}}.
> * Twelve {{int a = 'x'}} assignments under plain {{@TypeChecked}} (no
> extension) print the first ten {{Cannot assign value of type java.lang.String
> to variable of type int}} diagnostics and {{10 errors}}.
> * 6.0.0-beta-1 on {{TenOnly.groovy}} prints the ten diagnostics and {{10
> errors}} (no crash), so the tolerance case is a regression between
> 6.0.0-beta-1 and 6.0.0: GROOVY-12306 (fixed in 6.0.0-RC-1) made it reachable.
> The underlying defect is older: an extension that reports a fatal error
> overflows the same way on 6.0.0-beta-1 and 5.0.8. Current master is affected
> too.
> * {{groovyc --check --error-format=short --tolerance=0 TenOnly.groovy}}
> (unlimited tolerance) prints all ten diagnostics and {{10 errors}}; this is a
> workaround.
> Analysis. A script that compiles {{TenOnly.groovy}} through
> {{CompilationUnit}} and inspects the thrown
> {{MultipleCompilationErrorsException}} without rendering it shows 11 messages
> in the collector: ten {{SyntaxErrorMessage}} and one {{ExceptionMessage}}
> whose cause is a {{MultipleCompilationErrorsException}} carrying the same
> collector, raised from {{ErrorCollector.failIfErrors}} via
> {{StaticTypeCheckingVisitor.addStaticTypeError}} inside the extension's
> {{afterVisitMethod}}. So the tenth {{addStaticTypeError}} makes
> {{failIfErrors}} throw; {{AbstractTypeCheckingExtension.safeCall}} catches
> {{Exception}} and calls {{SourceUnit.addException}}, which records that
> exception as an {{ExceptionMessage}} in the same collector. Rendering the
> collector renders the exception's message, which renders the collector again,
> without end.
> A fix that works: {{safeCall}} rethrows a
> {{MultipleCompilationErrorsException}} that carries the source unit's own
> error collector instead of recording it; other exceptions are recorded as
> before. With that change the file above reports its ten diagnostics and {{10
> errors}}, {{--tolerance=3}} reports three, an extension reporting a fatal
> error reports one error, and {{--tolerance=0}} and plain {{@TypeChecked}} are
> unchanged. A pull request with a regression test ({{ErrorToleranceTest}})
> follows.
> Impact: any build or tool that compiles with an extension (the Groovy 6
> checkers, or a custom {{TypeCheckingDSL}}) and hits ten reports loses every
> diagnostic.
> Environment: Groovy 6.0.0 on BellSoft JDK 21.0.12, macOS 26.5 (arm64);
> reproduced on master at 9a1a0d0ccb with JDK 21.
--
This message was sent by Atlassian Jira
(v10.3.26#10030026)