RFR: 8292317: Missing null check for Iterator.forEachRemaining implementations
Stuart Marks
smarks at openjdk.org
Thu Nov 17 03:42:51 UTC 2022
On Tue, 15 Nov 2022 02:10:01 GMT, Jaikiran Pai <jpai at openjdk.org> wrote:
> Can I please get a review of this change which proposes to fix https://bugs.openjdk.org/browse/JDK-8292317?
>
> The `java.util.Iterator` has a `forEachRemaining(Consumer<? super E> action)` method. As per its contract, the implementations are expected to throw a `NullPointerException` if the passed `action` is `null`.
>
> `java.util.Collections` has a couple of places where it wraps the passed `action` into another and passes that wrapped `action` to the underlying `java.util.Iterator`'s default `forEachRemaining` implementation which is:
>
>
> Objects.requireNonNull(action);
> while (hasNext())
> action.accept(next());
>
> Since the passed `action` is now a non-null wrapper, the implementation goes ahead and advances the iterator to the next entry and invokes on the non-null `action` to carry out its action. That non-null wrapper action then calls the `null` user passed action and runs into an expected `NullPointerException`. However, at this point the iterator has already advanced and that is what the bug is.
>
> The commit in this PR introduces a trivial null check on the `action` very early in the call even before wrapping such an `action`. This prevents any further logic to execute if `action` is null.
>
> New test methods have been added to the existing test class `test/jdk/java/util/Collections/DelegatingIteratorForEachRemaining.java`. This test class was introduced in https://bugs.openjdk.org/browse/JDK-8205184 where this delegation logic was added for the `forEachRemaining` methods. These new test methods reproduce the failure and verify the fix.
test/jdk/java/util/Collections/DelegatingIteratorForEachRemaining.java line 235:
> 233: // verify the iterator didn't advance
> 234: Assert.assertTrue("Iterator unexpectedly doesn't have any entry", it.hasNext());
> 235: }
The checks in Collections.java look good.
The tests can be simplified, I think. The reproducers in the original bug report wrap an empty map in either an unmodifiable map or a checked map, so you could just test them with entrySet().iterator().forEachRemaining(null). Those cases do nothing in the current JDK when they indeed should throw NPE. Probably just test for NPE thrown/not-thrown instead of trying to ascertain the position of the iterator.
-------------
PR: https://git.openjdk.org/jdk/pull/11154
More information about the core-libs-dev
mailing list