apache / apache/maven-script-interpreter
Global System.out/System.err redirection and static lock serialize all script runs JVM-wide
- Dominant language
- Java
- Stars
- 14
- Forks
- 9
- Avg merge
- 5d 15h
- Merged PRs (30d)
- 2
Description
**Describe the bug**
Script evaluation redirects the JVM-global standard streams, and script execution is serialized behind a `static` lock to keep that redirection safe. Both have process-wide side effects.
The BeanShell and Groovy interpreters call `System.setOut`/`System.setErr` for the whole JVM during evaluation (BeanShellScriptInterpreter.java:108-158, GroovyScriptInterpreter.java:96-123). While a script runs:
- output written to `System.out`/`System.err` by **unrelated threads** in the same JVM (e.g. a logger writing to stderr, parallel build code) is silently captured into the script log; and
- a concurrently running script on another thread would otherwise clobber the redirected stream.
`ScriptRunner` guards against concurrent evaluation with a **`static` lock** (ScriptRunner.java:43, used at ScriptRunner.java:225). Consequences:
1. All `run(...)` calls across **all** `ScriptRunner` instances in the JVM are serialized, which is a bottleneck for parallel/CI builds that run hook scripts in multiple modules simultaneously.
2. Correctness of the global stream redirection depends entirely on every caller routing evaluation through that single static lock. Any future code path (or a caller invoking an interpreter directly) that evaluates outside the lock silently reintroduces cross-thread stream corruption.
**Eclipse/Maven environment** parallel builds; maven-script-interpreter 1.9-SNAPSHOT.
**Expected behavior**
Script output redirection affects only the current evaluation; unrelated threads keep writing to their own stdout/stderr, and concurrent script runs in the same JVM do not interfere.
**Actual behavior**
- JVM-wide `System.out`/`System.err` redirection during evaluation captures other threads' output into the script log.
- A single static lock serializes every `ScriptRunner.run(...)` call JVM-wide.
**Suggested approach**
- Use a per-instance lock instead of the static lock so independent `ScriptRunner` instances do not serialize each other.
- Redirect output via a stream that dispatches on the current thread/task (e.g. a `ThreadLocal`-based `OutputStream`) rather than mutating the process-global standard streams; restore the originals exactly as today in a `finally` block.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with ScriptRunner.java at lines 43 and 225, then read the evaluation sections of BeanShellScriptInterpreter.java (108-158) and GroovyScriptInterpreter.java (96-123). Trace the current stream restoration in finally blocks before assessing instance-level locking and thread/task-specific output. Done means unrelated JVM threads are not captured and independent script runs no longer serialize globally.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java
- Domain
- build-system
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100