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) {