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

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-configuration.git

commit 43f4dab021e9acb8db390db2ae80aa0cee4f9ee4
Author: Gary Gregory <garydgreg...@gmail.com>
AuthorDate: Sun Mar 17 09:23:59 2024 -0400

    [CONFIGURATION-841] StackOverflowError calling
    ListDelimiterHandler.flatten(Object, int) with a cyclical object tree
---
 src/changes/changes.xml                            |  3 +-
 .../convert/ListDelimiterHandler.java              |  5 +--
 .../TestPropertiesConfiguration.java               | 38 ++++++++++++++++++++++
 3 files changed, 41 insertions(+), 5 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 82dfd261..7645c202 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -26,7 +26,8 @@
     <release version="2.10.1" date="YYYY-MM-DD" description="Minor release 
with new features and updated dependencies.">
       <!-- FIX -->
       <action type="fix" issue="CONFIGURATION-840" dev="ggregory" due-to="Gary 
Gregory">StackOverflowError adding property in 
AbstractListDelimiterHandler.flattenIterator().</action>
-      <action type="fix" issue="CONFIGURATION-840" dev="ggregory" due-to="Bob 
Marinier, Gary Gregory">Version 2.10.0 fails java.lang.module.FindException: 
Module servlet.api not found.</action>
+      <action type="fix" issue="CONFIGURATION-840" dev="ggregory" due-to="Bob 
Marinier, Gary Gregory">java.lang.module.FindException: Module servlet.api not 
found.</action>
+      <action type="fix" issue="CONFIGURATION-841" dev="ggregory" due-to="Gary 
Gregory">StackOverflowError calling ListDelimiterHandler.flatten(Object, int) 
with a cyclical object tree.</action>
       <!-- UPDATE -->
       <action type="update" dev="ggregory" due-to="Dependabot">Bump 
jackson-databind from 2.16.1 to 2.17.0 #297, #303, #326, #331, #340, 
#378.</action>
       <action type="update" dev="ggregory" due-to="Dependabot">Bump 
log4j.version from 2.23.0 to 2.23.1 #379.</action>
diff --git 
a/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
 
b/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
index 902e9cd3..61b2407b 100644
--- 
a/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
+++ 
b/src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java
@@ -20,7 +20,6 @@ import java.util.Collection;
 import java.util.Collections;
 import java.util.IdentityHashMap;
 import java.util.List;
-import java.util.Set;
 
 /**
  * <p>
@@ -94,9 +93,7 @@ public interface ListDelimiterHandler {
      * @since 2.9.0
      */
     default Collection<?> flatten(final Object value, final int limit) {
-        final Set<Object> dejaVu = Collections.newSetFromMap(new 
IdentityHashMap<>());
-        dejaVu.add(value);
-        return AbstractListDelimiterHandler.flatten(this, value, limit, 
dejaVu);
+        return AbstractListDelimiterHandler.flatten(this, value, limit, 
Collections.newSetFromMap(new IdentityHashMap<>()));
     }
 
     /**
diff --git 
a/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
 
b/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
index 40462bed..da85e4bb 100644
--- 
a/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
+++ 
b/src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java
@@ -466,6 +466,22 @@ public class TestPropertiesConfiguration {
         assertEquals(object, result);
     }
 
+    @ParameterizedTest
+    @ValueSource(ints = { 0, 2, 4, 8, 16 })
+    public void testCompress840ArrayListCycle(final int size) {
+        final ArrayList<Object> object = new ArrayList<>();
+        for (int i = 0; i < size; i++) {
+            object.add(i);
+            object.add(object);
+            object.add(new ArrayList<>(object));
+        }
+        final Collection<?> result = testCompress840(object);
+        assertNotNull(result);
+        assertEquals(size, result.size());
+        object.add(object);
+        testCompress840(object);
+    }
+
     @Test
     public void testCompress840BeanContextServicesSupport() {
         testCompress840(new BeanContextServicesSupport());
@@ -492,6 +508,28 @@ public class TestPropertiesConfiguration {
         testCompress840(bcs);
     }
 
+    @ParameterizedTest
+    @ValueSource(ints = { 0, 2, 4, 8, 16 })
+    public void testCompress840Exception(final int size) {
+        final ArrayList<Object> object = new ArrayList<>();
+        final Exception bottom = new Exception();
+        object.add(bottom);
+        Exception top = bottom;
+        for (int i = 0; i < size; i++) {
+            object.add(i);
+            top = new Exception(top);
+            object.add(top);
+        }
+        if (bottom != top) {
+            // direct self-causation is not allowed.
+            bottom.initCause(top);
+        }
+        final Collection<?> result = testCompress840(object);
+        assertNotNull(result);
+        assertEquals(size * 2 + 1, result.size());
+        assertEquals(object, result);
+    }
+
     @ParameterizedTest
     @ValueSource(ints = { 0, 2, 4, 8, 16 })
     public void testCompress840Path(final int size) {

Reply via email to