[Bug]: Deep binary expressions overflow Spoon visitors
- Dominant language
- Java
- Stars
- 2k
- Forks
- 392
- Avg merge
- 11h 24m
- Merged PRs (30d)
- 36
Description
## Describe the bug
[OpenJDK](https://github.com/openjdk/jdk)'s valid [DeepStringConcat.java](https://github.com/openjdk/jdk/blob/be40b6bcdab37368ea3c769e575b36e290d0c6a1/test/langtools/tools/javac/DeepStringConcat.java) contains about 32,000 binary operators in one expression. `AstParentConsistencyChecker` and `ProcessingVisitor` recursively visit one operator per JVM stack frame.
The first overflow occurs while `AstParentConsistencyChecker` checks parent links. If that check is bypassed, `ProcessingVisitor` reaches the same limit while running processors.
A compatible fix may use small explicit stacks for consecutive binary operands in these two concrete visitors. Regardless of implementation, it must preserve Spoon's normal child order, callbacks before and after each child, and subclass override behavior. Malformed-parent diagnostics must not recursively pretty-print the same deep tree.
## Source code you are trying to analyze/transform
[DeepStringConcat.java](https://github.com/openjdk/jdk/blob/be40b6bcdab37368ea3c769e575b36e290d0c6a1/test/langtools/tools/javac/DeepStringConcat.java) from `openjdk/jdk@be40b6bcdab37368ea3c769e575b36e290d0c6a1`.
The file is a valid compiler stress test with a very deep string-concatenation expression.
## Source code for your Spoon processing
Building the model exposes the parent-consistency failure:
```java
Launcher launcher = new Launcher();
launcher.getEnvironment().setNoClasspath(true);
launcher.addInputResource("DeepStringConcat.java");
launcher.buildModel();
```
To expose the separate processor traversal failure without first running the parent checker, disable that check and run a processor:
```java
Launcher launcher = new Launcher();
launcher.getEnvironment().setNoClasspath(true);
launcher.getEnvironment().disableConsistencyChecks();
launcher.addInputResource("DeepStringConcat.java");
launcher.addProcessor(new AbstractProcessor>() {
@Override
public void process(CtBinaryOperator operator) {
}
});
launcher.run();
```
## Actual output
```text
java.lang.StackOverflowError
at spoon.reflect.visitor.CtScanner.visitCtBinaryOperator(...)
at spoon.support.reflect.code.CtBinaryOperatorImpl.accept(...)
at spoon.reflect.visitor.AstParentConsistencyChecker.scan(...)
... repeats ...
```
With consistency checks disabled, the processor run overflows in `ProcessingVisitor` instead.
## Expected output
Spoon validates and processes the legal deep expression with the normal JVM stack size.
## Spoon Version
Reproduced on Spoon `master` at [`06b187819380700384762416d15db2cc4f112175`](https://github.com/INRIA/spoon/commit/06b187819380700384762416d15db2cc4f112175).
## JVM Version
[OpenJDK](https://github.com/openjdk/jdk) 25.0.3
## What operating system are you using?
Linux x86-64
Contributor guide
Research direction
Start with the AstParentConsistencyChecker and ProcessingVisitor entry points, using DeepStringConcat.java and the provided Launcher examples to reproduce each StackOverflowError. Done means the deep expression validates and processes with normal stack size while preserving child order, callbacks, subclass overrides, and safe malformed-parent diagnostics.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100