From 836647231346e5d113fffaf33566ea3f618dbc9c Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Wed, 5 Jun 2024 15:26:02 +0200 Subject: [PATCH 1/2] [MNG-8066] Default exception handler does not handle recursion If there is a recursion in throwable causes, Maven will hang forever, instead to return. --- https://issues.apache.org/jira/browse/MNG-8066 --- .../exception/DefaultExceptionHandler.java | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java b/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java index 32c289c6699a..997656b30f0d 100644 --- a/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java +++ b/maven-core/src/main/java/org/apache/maven/exception/DefaultExceptionHandler.java @@ -22,7 +22,10 @@ import java.net.ConnectException; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.Collections; +import java.util.IdentityHashMap; import java.util.List; +import java.util.Set; import org.apache.maven.lifecycle.LifecycleExecutionException; import org.apache.maven.model.building.ModelProblem; @@ -87,13 +90,13 @@ */ @Component(role = ExceptionHandler.class) public class DefaultExceptionHandler implements ExceptionHandler { - + @Override public ExceptionSummary handleException(Throwable exception) { return handle("", exception); } private ExceptionSummary handle(String message, Throwable exception) { - String reference = getReference(exception); + String reference = getReference(Collections.newSetFromMap(new IdentityHashMap<>()), exception); List children = null; @@ -153,8 +156,11 @@ private ExceptionSummary handle(ModelProblem problem, String projectId) { } } - private String getReference(Throwable exception) { + private String getReference(Set dejaVu, Throwable exception) { String reference = ""; + if (!dejaVu.add(exception)) { + return reference; + } if (exception != null) { if (exception instanceof MojoExecutionException) { @@ -186,14 +192,14 @@ private String getReference(Throwable exception) { } if (StringUtils.isEmpty(reference)) { - reference = getReference(cause); + reference = getReference(dejaVu, cause); } if (StringUtils.isEmpty(reference)) { reference = exception.getClass().getSimpleName(); } } else if (exception instanceof LifecycleExecutionException) { - reference = getReference(exception.getCause()); + reference = getReference(dejaVu, exception.getCause()); } else if (isNoteworthyException(exception)) { reference = exception.getClass().getSimpleName(); } @@ -222,7 +228,8 @@ private boolean isNoteworthyException(Throwable exception) { private String getMessage(String message, Throwable exception) { String fullMessage = (message != null) ? message : ""; - // To break out of possible endless loop when getCause returns "this" + // To break out of possible endless loop when getCause returns "this", or dejaVu for n-level recursion (n>1) + Set dejaVu = Collections.newSetFromMap(new IdentityHashMap<>()); for (Throwable t = exception; t != null && t != t.getCause(); t = t.getCause()) { String exceptionMessage = t.getMessage(); @@ -246,6 +253,11 @@ private String getMessage(String message, Throwable exception) { } else if (!fullMessage.contains(exceptionMessage)) { fullMessage = join(fullMessage, exceptionMessage); } + + if (!dejaVu.add(t)) { + fullMessage = join(fullMessage, "[CIRCULAR REFERENCE]"); + break; + } } return fullMessage.trim(); From 6c6505044cfbe6ca55e5f54c118e105cf0d99256 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Thu, 6 Jun 2024 11:30:47 +0200 Subject: [PATCH 2/2] Add UT --- .../exception/DefaultExceptionHandlerTest.java | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java b/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java index 33fe83c21d6b..6a14ffa1a848 100644 --- a/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java +++ b/maven-core/src/test/java/org/apache/maven/exception/DefaultExceptionHandlerTest.java @@ -124,4 +124,20 @@ public synchronized Throwable getCause() { String expectedReference = "http://cwiki.apache.org/confluence/display/MAVEN/PluginContainerException"; assertEquals(expectedReference, summary.getReference()); } + + @Test + public void testHandleExceptionSelfReferencing() { + RuntimeException boom3 = new RuntimeException("BOOM3"); + RuntimeException boom2 = new RuntimeException("BOOM2", boom3); + RuntimeException boom1 = new RuntimeException("BOOM1", boom2); + boom3.initCause(boom1); + + DefaultExceptionHandler handler = new DefaultExceptionHandler(); + ExceptionSummary summary = handler.handleException(boom1); + + assertEquals("BOOM1: BOOM2: BOOM3: [CIRCULAR REFERENCE]", summary.getMessage()); + assertEquals("", summary.getReference()); + assertEquals(0, summary.getChildren().size()); + assertEquals(boom1, summary.getException()); + } }