Skip to content

Commit 43f4dab

Browse files
committed
[CONFIGURATION-841] StackOverflowError calling
ListDelimiterHandler.flatten(Object, int) with a cyclical object tree
1 parent a177758 commit 43f4dab

3 files changed

Lines changed: 41 additions & 5 deletions

File tree

src/changes/changes.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
<release version="2.10.1" date="YYYY-MM-DD" description="Minor release with new features and updated dependencies.">
2727
<!-- FIX -->
2828
<action type="fix" issue="CONFIGURATION-840" dev="ggregory" due-to="Gary Gregory">StackOverflowError adding property in AbstractListDelimiterHandler.flattenIterator().</action>
29-
<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>
29+
<action type="fix" issue="CONFIGURATION-840" dev="ggregory" due-to="Bob Marinier, Gary Gregory">java.lang.module.FindException: Module servlet.api not found.</action>
30+
<action type="fix" issue="CONFIGURATION-841" dev="ggregory" due-to="Gary Gregory">StackOverflowError calling ListDelimiterHandler.flatten(Object, int) with a cyclical object tree.</action>
3031
<!-- UPDATE -->
3132
<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>
3233
<action type="update" dev="ggregory" due-to="Dependabot">Bump log4j.version from 2.23.0 to 2.23.1 #379.</action>

src/main/java/org/apache/commons/configuration2/convert/ListDelimiterHandler.java

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.Collections;
2121
import java.util.IdentityHashMap;
2222
import java.util.List;
23-
import java.util.Set;
2423

2524
/**
2625
* <p>
@@ -94,9 +93,7 @@ public interface ListDelimiterHandler {
9493
* @since 2.9.0
9594
*/
9695
default Collection<?> flatten(final Object value, final int limit) {
97-
final Set<Object> dejaVu = Collections.newSetFromMap(new IdentityHashMap<>());
98-
dejaVu.add(value);
99-
return AbstractListDelimiterHandler.flatten(this, value, limit, dejaVu);
96+
return AbstractListDelimiterHandler.flatten(this, value, limit, Collections.newSetFromMap(new IdentityHashMap<>()));
10097
}
10198

10299
/**

src/test/java/org/apache/commons/configuration2/TestPropertiesConfiguration.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -466,6 +466,22 @@ public void testCompress840ArrayList(final int size) {
466466
assertEquals(object, result);
467467
}
468468

469+
@ParameterizedTest
470+
@ValueSource(ints = { 0, 2, 4, 8, 16 })
471+
public void testCompress840ArrayListCycle(final int size) {
472+
final ArrayList<Object> object = new ArrayList<>();
473+
for (int i = 0; i < size; i++) {
474+
object.add(i);
475+
object.add(object);
476+
object.add(new ArrayList<>(object));
477+
}
478+
final Collection<?> result = testCompress840(object);
479+
assertNotNull(result);
480+
assertEquals(size, result.size());
481+
object.add(object);
482+
testCompress840(object);
483+
}
484+
469485
@Test
470486
public void testCompress840BeanContextServicesSupport() {
471487
testCompress840(new BeanContextServicesSupport());
@@ -492,6 +508,28 @@ public void testCompress840BeanContextSupport() {
492508
testCompress840(bcs);
493509
}
494510

511+
@ParameterizedTest
512+
@ValueSource(ints = { 0, 2, 4, 8, 16 })
513+
public void testCompress840Exception(final int size) {
514+
final ArrayList<Object> object = new ArrayList<>();
515+
final Exception bottom = new Exception();
516+
object.add(bottom);
517+
Exception top = bottom;
518+
for (int i = 0; i < size; i++) {
519+
object.add(i);
520+
top = new Exception(top);
521+
object.add(top);
522+
}
523+
if (bottom != top) {
524+
// direct self-causation is not allowed.
525+
bottom.initCause(top);
526+
}
527+
final Collection<?> result = testCompress840(object);
528+
assertNotNull(result);
529+
assertEquals(size * 2 + 1, result.size());
530+
assertEquals(object, result);
531+
}
532+
495533
@ParameterizedTest
496534
@ValueSource(ints = { 0, 2, 4, 8, 16 })
497535
public void testCompress840Path(final int size) {

0 commit comments

Comments
 (0)