[
https://issues.apache.org/jira/browse/MNG-8066?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Tamas Cservenak updated MNG-8066:
---------------------------------
Fix Version/s: 3.9.8
4.0.0-beta-4
> Maven hangs on self-referencing exceptions
> ------------------------------------------
>
> Key: MNG-8066
> URL: https://issues.apache.org/jira/browse/MNG-8066
> Project: Maven
> Issue Type: Bug
> Reporter: François Guillot
> Priority: Major
> Fix For: 3.9.8, 4.0.0-beta-4
>
>
> If the code executed by Maven throws a self-referencing exception, such as
> {code:java}
> RuntimeException selfReferencingException = new RuntimeException("BOOM self");
> selfReferencingException.initCause(new Exception("BOOM cause",
> selfReferencingException));
> throw selfReferencingException;
> {code}
> For instance, if this code is added to an `AbstractExecutionListener`, which
> is added to the running build:
> {code:java}
> import org.apache.maven.execution.AbstractExecutionListener;
> import org.apache.maven.execution.ExecutionListener;
> import org.apache.maven.execution.ExecutionEvent;
> public class FailingExecutionListener extends AbstractExecutionListener {
> private final ExecutionListener delegate;
> public FailingExecutionListener(ExecutionListener delegate) {
> this.delegate = delegate;
> }
> @Override
> public void sessionStarted(ExecutionEvent event) {
> if (delegate != null) {
> delegate.sessionStarted(event);
> }
> RuntimeException selfReferencingException = new RuntimeException("BOOM
> self");
> selfReferencingException.initCause(new Exception("BOOM cause",
> selfReferencingException));
> throw selfReferencingException;
> }
> }
> {code}
> Maven hangs at the end of the build, in `DefaultExceptionHandler`.
> The code in `DefaultExceptionHandler#getMessage` iterates on a given
> throwable and its causes. It checks if the cause is not the same throwable,
> but doesn't protect against a 'two-level' recursion like shown above.
> Note that when printing a stacktrace, Java itself protects against this via
> the use of a
> {code:java}
> Set<Throwable> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
> {code}
> and stops the recursion if encountering an already seen throwable.
> A way to fix this would be to replace the offending cause with a replacement
> with no cause, such as in
> {code:java}
> private static Throwable patchCircularCause(Throwable current, Throwable
> parent) {
> try {
> Field causeField = Throwable.class.getDeclaredField("cause");
> causeField.setAccessible(true);
> Throwable replacement = new Throwable("[CIRCULAR REFERENCE: " +
> current + "]");
> replacement.setStackTrace(current.getStackTrace());
> causeField.set(parent, replacement);
> return replacement;
> } catch (NoSuchFieldException | IllegalAccessException e) {
> // Couldn't replace the cause, let's return the actual exception.
> return current;
> }
> }
> {code}
--
This message was sent by Atlassian Jira
(v8.20.10#820010)