This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git


The following commit(s) were added to refs/heads/master by this push:
     new 9ce85ef4f4 [MNG-8066] Default exception handler does not handle 
recursion (#1558)
9ce85ef4f4 is described below

commit 9ce85ef4f4469287aae8a1e43e3d6960d41b746c
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Thu Jun 6 12:31:03 2024 +0200

    [MNG-8066] Default exception handler does not handle recursion (#1558)
    
    If there is a recursion in throwable causes, Maven will hang forever, 
instead to return.
    
    ---
    
    https://issues.apache.org/jira/browse/MNG-8066
---
 .../maven/exception/DefaultExceptionHandler.java   | 24 ++++++++++++++++------
 .../exception/DefaultExceptionHandlerTest.java     | 16 +++++++++++++++
 2 files changed, 34 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 b6c4e8cca5..059e1c8e17 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
@@ -25,7 +25,10 @@ import java.io.IOException;
 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;
@@ -88,13 +91,13 @@ Plugins:
 @Named
 @Singleton
 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<ExceptionSummary> children = null;
 
@@ -156,8 +159,11 @@ public class DefaultExceptionHandler implements 
ExceptionHandler {
         }
     }
 
-    private String getReference(Throwable exception) {
+    private String getReference(Set<Throwable> dejaVu, Throwable exception) {
         String reference = "";
+        if (!dejaVu.add(exception)) {
+            return reference;
+        }
 
         if (exception != null) {
             if (exception instanceof MojoExecutionException) {
@@ -187,14 +193,14 @@ public class DefaultExceptionHandler implements 
ExceptionHandler {
                 }
 
                 if (reference == null || reference.isEmpty()) {
-                    reference = getReference(cause);
+                    reference = getReference(dejaVu, cause);
                 }
 
                 if (reference == null || reference.isEmpty()) {
                     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 @@ public class DefaultExceptionHandler implements 
ExceptionHandler {
     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<Throwable> dejaVu = Collections.newSetFromMap(new 
IdentityHashMap<>());
         for (Throwable t = exception; t != null && t != t.getCause(); t = 
t.getCause()) {
             String exceptionMessage = t.getMessage();
 
@@ -247,6 +254,11 @@ public class DefaultExceptionHandler implements 
ExceptionHandler {
             } else if (!fullMessage.contains(exceptionMessage)) {
                 fullMessage = join(fullMessage, exceptionMessage);
             }
+
+            if (!dejaVu.add(t)) {
+                fullMessage = join(fullMessage, "[CIRCULAR REFERENCE]");
+                break;
+            }
         }
 
         return fullMessage.trim();
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 f3f6075533..c9a84014d2 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
@@ -123,4 +123,20 @@ class DefaultExceptionHandlerTest {
         String expectedReference = 
"http://cwiki.apache.org/confluence/display/MAVEN/PluginContainerException";;
         assertEquals(expectedReference, summary.getReference());
     }
+
+    @Test
+    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());
+    }
 }

Reply via email to