Skip to content

Commit f995b98

Browse files
Vasiliy Mikhailovakarnokd
andauthored
Fix NullPointerException in AppendOnlyLinkedArrayList.forEachWhile on a full last chunk (#8174)
* Fix NullPointerException in AppendOnlyLinkedArrayList.forEachWhile on a full last chunk forEachWhile(S, BiPredicate) walks the linked chunks and, after iterating a chunk, follows the next-chunk pointer stored at a[capacity]. When the list size is exactly a multiple of the chunk capacity the last chunk is full but its next-chunk pointer has not been allocated yet (it is null), so `a` becomes null and the next iteration throws NullPointerException reading a[0]. Stop traversal when the next chunk is null. Adds a regression test that fails before this change (NPE) and passes after it. * Refactor forEachWhile to use lambda in test Refactor test method to use lambda expression. --------- Co-authored-by: David Karnok <akarnokd@gmail.com>
1 parent f08aa83 commit f995b98

2 files changed

Lines changed: 22 additions & 0 deletions

File tree

src/main/java/io/reactivex/rxjava4/internal/util/AppendOnlyLinkedArrayList.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,9 @@ public <S> void forEachWhile(S state, BiPredicate<? super S, ? super T> consumer
175175
}
176176
}
177177
a = (Object[])a[c];
178+
if (a == null) {
179+
return;
180+
}
178181
}
179182
}
180183
}

src/test/java/io/reactivex/rxjava4/internal/util/MiscUtilTest.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,4 +236,23 @@ public void appendOnlyLinkedArrayListForEachWhileBiAll() throws Throwable {
236236
public void queueDrainHelperUtility() {
237237
TestHelper.checkUtilityClass(QueueDrainHelper.class);
238238
}
239+
240+
@Test
241+
public void appendOnlyLinkedArrayListForEachWhileBiFullChunkNoNext() throws Throwable {
242+
// Fill exactly capacity elements in one chunk; no next chunk exists (a[c] == null).
243+
// The predicate returns false for all elements so the loop must traverse past the full chunk.
244+
AppendOnlyLinkedArrayList<Integer> list = new AppendOnlyLinkedArrayList<>(2);
245+
246+
list.add(1);
247+
list.add(2);
248+
249+
final List<Integer> out = new ArrayList<>();
250+
251+
list.forEachWhile(null, (state, value) -> {
252+
out.add(value);
253+
return false; // never terminate early
254+
});
255+
256+
assertEquals(Arrays.asList(1, 2), out);
257+
}
239258
}

0 commit comments

Comments
 (0)