[ 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: 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 > Components: Core > Reporter: François Guillot > Assignee: Tamas Cservenak > Priority: Major > Fix For: 4.0.0, 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)