INRIA / INRIA/spoon

[Bug]: Deep binary expressions overflow Spoon visitors

Open
#6,804 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.