From 4ef2067d0c3ac10be0ac8aec794a2b2b742052c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fridrich=20=C5=A0trba?= <fridrich.strba@bluewin.ch>
Date: Thu, 28 Mar 2024 08:59:09 +0100
Subject: [PATCH 2/2] [CONFIGURATION-841] Fix StackOverflow with a cyclical
 object tree

---
 .../configuration/PropertyConverter.java      | 22 +++++++++++++------
 .../configuration/TestPropertyConverter.java  | 15 +++++++++++++
 2 files changed, 30 insertions(+), 7 deletions(-)

diff --git a/src/main/java/org/apache/commons/configuration/PropertyConverter.java b/src/main/java/org/apache/commons/configuration/PropertyConverter.java
index 650c55b5..683327ac 100644
--- a/src/main/java/org/apache/commons/configuration/PropertyConverter.java
+++ b/src/main/java/org/apache/commons/configuration/PropertyConverter.java
@@ -33,11 +33,14 @@ import java.text.SimpleDateFormat;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Date;
+import java.util.IdentityHashMap;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 import org.apache.commons.lang.BooleanUtils;
 import org.apache.commons.lang.StringUtils;
@@ -944,7 +947,7 @@ public final class PropertyConverter
      */
     public static Iterator<?> toIterator(Object value, char delimiter)
     {
-        return flatten(value, delimiter).iterator();
+        return flatten(value, delimiter, Collections.newSetFromMap(new IdentityHashMap<Object,Boolean>())).iterator();
     }
 
     /**
@@ -970,8 +973,9 @@ public final class PropertyConverter
      * @return a &quot;flat&quot; collection containing all primitive values of
      *         the passed in object
      */
-    private static Collection<?> flatten(Object value, char delimiter)
+    private static Collection<?> flatten(Object value, char delimiter, final Set<Object> dejaVu)
     {
+        dejaVu.add(value);
         if (value instanceof String)
         {
             String s = (String) value;
@@ -989,11 +993,11 @@ public final class PropertyConverter
         }
         else if (value instanceof Iterable)
         {
-            flattenIterator(result, ((Iterable<?>) value).iterator(), delimiter);
+            flattenIterator(result, ((Iterable<?>) value).iterator(), delimiter, dejaVu);
         }
         else if (value instanceof Iterator)
         {
-            flattenIterator(result, (Iterator<?>) value, delimiter);
+            flattenIterator(result, (Iterator<?>) value, delimiter, dejaVu);
         }
         else if (value != null)
         {
@@ -1001,7 +1005,7 @@ public final class PropertyConverter
             {
                 for (int len = Array.getLength(value), idx = 0; idx < len; idx++)
                 {
-                    result.addAll(flatten(Array.get(value, idx), delimiter));
+                    result.addAll(flatten(Array.get(value, idx), delimiter, Collections.newSetFromMap(new IdentityHashMap<Object,Boolean>())));
                 }
             }
             else
@@ -1021,11 +1025,15 @@ public final class PropertyConverter
      * @param it the iterator to process
      * @param delimiter the delimiter for String values
      */
-    private static void flattenIterator(Collection<Object> target, Iterator<?> it, char delimiter)
+    private static void flattenIterator(Collection<Object> target, Iterator<?> it, char delimiter, Set<Object> dejaVue)
     {
         while (it.hasNext())
         {
-            target.addAll(flatten(it.next(), delimiter));
+            final Object next = it.next();
+            if (!dejaVue.contains(next))
+            {
+                target.addAll(flatten(next, delimiter, dejaVue));
+            }
         }
     }
 
diff --git a/src/test/java/org/apache/commons/configuration/TestPropertyConverter.java b/src/test/java/org/apache/commons/configuration/TestPropertyConverter.java
index c1e7bbf1..d9f284ab 100644
--- a/src/test/java/org/apache/commons/configuration/TestPropertyConverter.java
+++ b/src/test/java/org/apache/commons/configuration/TestPropertyConverter.java
@@ -26,6 +26,7 @@ import java.lang.annotation.ElementType;
 import java.math.BigDecimal;
 import java.nio.file.FileSystems;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
@@ -162,6 +163,20 @@ public class TestPropertyConverter
 		config.addProperty("foo", path);
     }
 
+    @Test
+    public void testArrayListCycle()
+    {
+        PropertiesConfiguration config = new PropertiesConfiguration();
+        final ArrayList<Object> object = new ArrayList<Object>();
+        for (int i = 0; i < 16; i++)
+        {
+            object.add(i);
+            object.add(object);
+            object.add(new ArrayList<Object>(object));
+        }
+        config.addProperty("foo", object);
+    }
+
     /**
      * Tests the interpolation features.
      */
-- 
2.44.0

