diff --git a/jdk/src/share/classes/java/util/stream/SortedOps.java b/jdk/src/share/classes/java/util/stream/SortedOps.java index 9df65e352e2..c9d04bd0763 100644 --- a/jdk/src/share/classes/java/util/stream/SortedOps.java +++ b/jdk/src/share/classes/java/util/stream/SortedOps.java @@ -277,8 +277,10 @@ final class SortedOps { } } + private static final String BAD_SIZE = "Stream size exceeds max array size"; + /** - * {@link ForkJoinTask} for implementing sort on SIZED reference streams. + * {@link Sink} for implementing sort on SIZED reference streams. */ private static final class SizedRefSortingSink extends Sink.ChainedReference { private final Comparator comparator; @@ -293,16 +295,12 @@ final class SortedOps { @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); array = (T[]) new Object[(int) size]; } @Override public void end() { - // Need to use offset rather than array.length since the downstream - // many be short-circuiting - // @@@ A better approach is to know if the downstream short-circuits - // and check sink.cancellationRequested Arrays.sort(array, 0, offset, comparator); downstream.begin(offset); for (int i = 0; i < offset; i++) @@ -331,6 +329,8 @@ final class SortedOps { @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); list = (size >= 0) ? new ArrayList((int) size) : new ArrayList(); } @@ -363,7 +363,7 @@ final class SortedOps { @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); array = new int[(int) size]; } @@ -395,6 +395,8 @@ final class SortedOps { @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); b = (size > 0) ? new SpinedBuffer.OfInt((int) size) : new SpinedBuffer.OfInt(); } @@ -428,7 +430,7 @@ final class SortedOps { @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); array = new long[(int) size]; } @@ -460,6 +462,8 @@ final class SortedOps { @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); b = (size > 0) ? new SpinedBuffer.OfLong((int) size) : new SpinedBuffer.OfLong(); } @@ -493,7 +497,7 @@ final class SortedOps { @Override public void begin(long size) { if (size >= Nodes.MAX_ARRAY_SIZE) - throw new IllegalArgumentException("Stream size exceeds max array size"); + throw new IllegalArgumentException(BAD_SIZE); array = new double[(int) size]; } @@ -525,6 +529,8 @@ final class SortedOps { @Override public void begin(long size) { + if (size >= Nodes.MAX_ARRAY_SIZE) + throw new IllegalArgumentException(BAD_SIZE); b = (size > 0) ? new SpinedBuffer.OfDouble((int) size) : new SpinedBuffer.OfDouble(); } diff --git a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java index 6c8cab21825..960e614fdc4 100644 --- a/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java +++ b/jdk/test/java/util/stream/test/org/openjdk/tests/java/util/stream/SortedOpTest.java @@ -26,6 +26,8 @@ import org.testng.annotations.Test; import java.util.*; import java.util.Spliterators; +import java.util.function.Function; +import java.util.function.Supplier; import java.util.stream.*; import static java.util.stream.LambdaTestHelpers.*; @@ -37,6 +39,69 @@ import static java.util.stream.LambdaTestHelpers.*; */ @Test public class SortedOpTest extends OpTestCase { + + public void testRefStreamTooLarge() { + Function> f = s -> + // Clear the SORTED flag + s.mapToObj(i -> i) + .sorted(); + + testStreamTooLarge(f, Stream::findFirst); + } + + public void testIntStreamTooLarge() { + Function f = s -> + // Clear the SORTED flag + s.mapToInt(i -> (int) i) + .sorted(); + + testStreamTooLarge(f, IntStream::findFirst); + } + + public void testLongStreamTooLarge() { + Function f = s -> + // Clear the SORTED flag + s.map(i -> i) + .sorted(); + + testStreamTooLarge(f, LongStream::findFirst); + } + + public void testDoubleStreamTooLarge() { + Function f = s -> + // Clear the SORTED flag + s.mapToDouble(i -> (double) i) + .sorted(); + + testStreamTooLarge(f, DoubleStream::findFirst); + } + + > void testStreamTooLarge(Function s, + Function terminal) { + // Set up conditions for a large input > maximum array size + Supplier input = () -> LongStream.range(0, 1L + Integer.MAX_VALUE); + + // Transformation functions + List> transforms = Arrays.asList( + ls -> ls, + ls -> ls.parallel(), + // Clear the SIZED flag + ls -> ls.limit(Long.MAX_VALUE), + ls -> ls.limit(Long.MAX_VALUE).parallel()); + + for (Function transform : transforms) { + RuntimeException caught = null; + try { + terminal.apply(s.apply(transform.apply(input.get()))); + } catch (RuntimeException e) { + caught = e; + } + assertNotNull(caught, "Expected an instance of exception IllegalArgumentException but no exception thrown"); + assertTrue(caught instanceof IllegalArgumentException, + String.format("Expected an instance of exception IllegalArgumentException but got %s", caught)); + } + } + public void testSorted() { assertCountSum(countTo(0).stream().sorted(), 0, 0); assertCountSum(countTo(10).stream().sorted(), 10, 55);