diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 889861cac1..d1b5a32531 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -24,6 +24,7 @@ + Avoid integer overflow when retrieving the last partition from ListUtils.partition(). Fix inverted fixed-size guard in FixedSizeSortedMap.putAll (#722). Keep existing sort order in ComparatorChain.setComparator (#723). Update the index on remove via IndexedCollection.iterator() (#724). diff --git a/src/main/java/org/apache/commons/collections4/ListUtils.java b/src/main/java/org/apache/commons/collections4/ListUtils.java index d78515c802..9a1cbfac97 100644 --- a/src/main/java/org/apache/commons/collections4/ListUtils.java +++ b/src/main/java/org/apache/commons/collections4/ListUtils.java @@ -123,7 +123,7 @@ public List get(final int index) { throw new IndexOutOfBoundsException("Index " + index + " must be less than size " + listSize); } final int start = index * size; - final int end = Math.min(start + size, list.size()); + final int end = start + Math.min(size, list.size() - start); return list.subList(start, end); } diff --git a/src/test/java/org/apache/commons/collections4/ListUtilsTest.java b/src/test/java/org/apache/commons/collections4/ListUtilsTest.java index f64d37e422..1ffe4b52a6 100644 --- a/src/test/java/org/apache/commons/collections4/ListUtilsTest.java +++ b/src/test/java/org/apache/commons/collections4/ListUtilsTest.java @@ -25,6 +25,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.AbstractList; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -340,6 +341,27 @@ void testPartition() { assertEquals(strings, partitionMax.get(0)); } + @Test + void testPartitionLastPartitionDoesNotOverflow() { + final List list = new AbstractList() { + @Override + public Integer get(final int index) { + return index; + } + + @Override + public int size() { + return Integer.MAX_VALUE; + } + }; + final int size = (1 << 30) + 1; + final List> partition = ListUtils.partition(list, size); + + assertEquals(2, partition.size()); + assertEquals(Integer.MAX_VALUE - size, partition.get(1).size()); + assertEquals(size, partition.get(1).get(0)); + } + @Test void testPredicatedList() { final Predicate predicate = String.class::isInstance;