undefect. CWE-407 — 63 sites patched across 27 ecosystems

Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
This commit is contained in:
russell@unturf.com 2026-03-26 17:11:57 -04:00
commit 0a580b313d
70422 changed files with 17213626 additions and 0 deletions

View file

@ -0,0 +1,88 @@
/*
* Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 4715206
* @summary Ensure that addAll method can cope with underestimate by size().
* @author Josh Bloch
*/
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;
import java.util.WeakHashMap;
public class AddAll {
public static void main(String[] args) {
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
new ArrayList().addAll(m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
new LinkedList().addAll(m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
new Vector().addAll(m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
List list = new ArrayList();
list.add("inka"); list.add("dinka"); list.add("doo");
list.addAll(1, m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
List list = new LinkedList();
list.add("inka"); list.add("dinka"); list.add("doo");
list.addAll(1, m.keySet());
}
for (int j = 0; j < 1; j++) {
Map m = new WeakHashMap(100000);
for (int i = 0; i < 100000; i++)
m.put(new Object(), Boolean.TRUE);
List list = new ArrayList();
list.add("inka"); list.add("dinka"); list.add("doo");
list.addAll(1, m.keySet());
}
}
}

View file

@ -0,0 +1,214 @@
/*
* Copyright 2016 Google, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8146568
* @summary brittle white box test of internal array management
* @modules java.base/java.util:open
* @run testng ArrayManagement
*/
import java.lang.reflect.Field;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.SplittableRandom;
import org.testng.annotations.Test;
import static org.testng.Assert.*;
public class ArrayManagement {
static final int DEFAULT_CAPACITY = 10;
static final Field ELEMENT_DATA;
static final Field MODCOUNT;
static final SplittableRandom rnd = new SplittableRandom();
static {
try {
ELEMENT_DATA = ArrayList.class.getDeclaredField("elementData");
ELEMENT_DATA.setAccessible(true);
MODCOUNT = AbstractList.class.getDeclaredField("modCount");
MODCOUNT.setAccessible(true);
} catch (ReflectiveOperationException huh) {
throw new AssertionError(huh);
}
}
static Object[] elementData(ArrayList<?> list) {
try {
return (Object[]) ELEMENT_DATA.get(list);
} catch (ReflectiveOperationException huh) {
throw new AssertionError(huh);
}
}
static int modCount(ArrayList<?> list) {
try {
return MODCOUNT.getInt(list);
} catch (ReflectiveOperationException huh) {
throw new AssertionError(huh);
}
}
static int capacity(ArrayList<?> list) {
return elementData(list).length;
}
static int newCapacity(int oldCapacity) {
return oldCapacity + (oldCapacity >> 1);
}
static void ensureCapacity(ArrayList<Object> list, int capacity) {
int oldCapacity = capacity(list);
int oldModCount = modCount(list);
list.ensureCapacity(capacity);
assertTrue(capacity(list) >= capacity || capacity(list) == 0);
assertEquals(modCount(list),
(capacity(list) == oldCapacity)
? oldModCount
: oldModCount + 1);
}
static List<Object> singletonList() {
return Collections.singletonList(Boolean.TRUE);
}
/** Opportunistically randomly test various add operations. */
static void addOneElement(ArrayList<Object> list) {
int size = list.size();
int modCount = modCount(list);
switch (rnd.nextInt(4)) {
case 0: assertTrue(list.add(Boolean.TRUE)); break;
case 1: list.add(size, Boolean.TRUE); break;
case 2: assertTrue(list.addAll(singletonList())); break;
case 3: assertTrue(list.addAll(size, singletonList())); break;
default: throw new AssertionError();
}
assertEquals(modCount(list), modCount + 1);
assertEquals(list.size(), size + 1);
}
@Test public void defaultCapacity() {
ArrayList<Object> list = new ArrayList<>();
assertEquals(capacity(new ArrayList<Object>()), 0);
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
addOneElement(list);
assertEquals(capacity(list), DEFAULT_CAPACITY);
}
addOneElement(list);
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY));
}
@Test public void defaultCapacityEnsureCapacity() {
ArrayList<Object> list = new ArrayList<>();
for (int i = 0; i <= DEFAULT_CAPACITY; i++) {
ensureCapacity(list, i); // no-op!
assertEquals(capacity(list), 0);
}
for (int i = 0; i < DEFAULT_CAPACITY; i++) {
addOneElement(list);
assertEquals(capacity(list), DEFAULT_CAPACITY);
}
addOneElement(list);
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY));
{
int capacity = capacity(list);
ensureCapacity(list, capacity + 1);
assertEquals(capacity(list), newCapacity(capacity));
}
{
int capacity = capacity(list);
ensureCapacity(list, 3 * capacity);
assertEquals(capacity(list), 3 * capacity);
}
}
@Test public void ensureCapacityBeyondDefaultCapacity() {
ArrayList<Object> list = new ArrayList<>();
list.ensureCapacity(DEFAULT_CAPACITY + 1);
assertEquals(capacity(list), DEFAULT_CAPACITY + 1);
for (int i = 0; i < DEFAULT_CAPACITY + 1; i++) {
addOneElement(list);
assertEquals(capacity(list), DEFAULT_CAPACITY + 1);
}
addOneElement(list);
assertEquals(capacity(list), newCapacity(DEFAULT_CAPACITY + 1));
}
@Test public void explicitZeroCapacity() {
ArrayList<Object> list = new ArrayList<>(0);
assertEquals(capacity(list), 0);
addOneElement(list);
assertEquals(capacity(list), 1);
addOneElement(list);
assertEquals(capacity(list), 2);
addOneElement(list);
assertEquals(capacity(list), 3);
addOneElement(list);
assertEquals(capacity(list), 4);
addOneElement(list);
assertEquals(capacity(list), 6);
addOneElement(list);
assertEquals(capacity(list), 6);
addOneElement(list);
assertEquals(capacity(list), 9);
list.clear();
assertEquals(capacity(list), 9);
}
@Test public void explicitLargeCapacity() {
int n = DEFAULT_CAPACITY * 3;
ArrayList<Object> list = new ArrayList<>(n);
assertEquals(capacity(list), n);
ensureCapacity(list, 0);
ensureCapacity(list, n);
for (int i = 0; i < n; i++) addOneElement(list);
assertEquals(capacity(list), n);
addOneElement(list);
assertEquals(capacity(list), newCapacity(n));
}
@Test public void emptyArraysAreShared() {
assertSame(elementData(new ArrayList<Object>()),
elementData(new ArrayList<Object>()));
assertSame(elementData(new ArrayList<Object>(0)),
elementData(new ArrayList<Object>(0)));
}
@Test public void emptyArraysDifferBetweenDefaultAndExplicit() {
assertNotSame(elementData(new ArrayList<Object>()),
elementData(new ArrayList<Object>(0)));
}
@Test public void negativeCapacity() {
for (int capacity : new int[] { -1, Integer.MIN_VALUE }) {
try {
new ArrayList<Object>(capacity);
fail("should throw");
} catch (IllegalArgumentException success) {}
}
}
}

View file

@ -0,0 +1,70 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 6533203
* @summary AbstractList.ListItr.add might corrupt iterator state if enclosing add throws
*/
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
@SuppressWarnings({"serial","unchecked"})
public class Bug6533203 {
void test(String[] args) throws Throwable {
final List<Integer> superstitious = new ArrayList<>() {
public void add(int index, Integer i) {
if (i == 13) throw new Error("unlucky");
else super.add(index, i); }};
final ListIterator it = superstitious.listIterator(0);
equal(it.nextIndex(), 0);
THROWS(Error.class, new F(){void f(){it.add(13);}});
equal(it.nextIndex(), 0);
}
//--------------------- Infrastructure ---------------------------
volatile int passed = 0, failed = 0;
void pass() {passed++;}
void fail() {failed++; Thread.dumpStack();}
void fail(String msg) {System.out.println(msg); fail();}
void unexpected(Throwable t) {failed++; t.printStackTrace();}
void check(boolean cond) {if (cond) pass(); else fail();}
void equal(Object x, Object y) {
if (x == null ? y == null : x.equals(y)) pass();
else fail(x + " not equal to " + y);}
public static void main(String[] args) throws Throwable {
new Bug6533203().instanceMain(args);}
void instanceMain(String[] args) throws Throwable {
try {test(args);} catch (Throwable t) {unexpected(t);}
System.out.printf("%nPassed = %d, failed = %d%n%n", passed, failed);
if (failed > 0) throw new AssertionError("Some tests failed");}
abstract class F {abstract void f() throws Throwable;}
void THROWS(Class<? extends Throwable> k, F... fs) {
for (F f : fs)
try {f.f(); fail("Expected " + k.getName() + " not thrown");}
catch (Throwable t) {
if (k.isAssignableFrom(t.getClass())) pass();
else unexpected(t);}}
}

View file

@ -0,0 +1,43 @@
/*
* Copyright 2016 Google, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8146568
* @summary repro for: NegativeArraySizeException in ArrayList.grow(int)
* @run main/manual/othervm -Xmx17g Bug8146568
* @requires os.maxMemory>17G
*/
public class Bug8146568 {
public static void main(String[] args) {
int size = Integer.MAX_VALUE - 2;
java.util.ArrayList<Object> huge = new java.util.ArrayList<>(size);
for (int i = 0; i < size; i++)
huge.add(null);
try {
huge.addAll(huge);
throw new Error("expected OutOfMemoryError not thrown");
} catch (OutOfMemoryError success) {}
}
}

View file

@ -0,0 +1,64 @@
/*
* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 6992121
* @summary Test the ArrayList.ensureCapacity() and Vector.ensureCapacity
* method with negative minimumCapacity input argument.
*/
import java.util.ArrayList;
import java.util.Vector;
public class EnsureCapacity {
public static void main(String[] args) {
testArrayList();
testVector();
}
private static void checkCapacity(int before, int after) {
if (before != after) {
throw new RuntimeException("capacity is expected to be unchanged: " +
"before=" + before + " after=" + after);
}
}
private static void testArrayList() {
ArrayList<String> al = new ArrayList<String>();
al.add("abc");
al.ensureCapacity(Integer.MIN_VALUE);
// there is no method to query the capacity of ArrayList
// so before and after capacity are not checked
}
private static void testVector() {
Vector<String> vector = new Vector<String>();
vector.add("abc");
int cap = vector.capacity();
vector.ensureCapacity(Integer.MIN_VALUE);
checkCapacity(cap, vector.capacity());
}
}

View file

@ -0,0 +1,710 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @summary micro-benchmark correctness mode
* @run main IteratorMicroBenchmark iterations=1 size=8 warmup=0
*/
import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.stream.Collectors.toList;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Spliterator;
import java.util.Vector;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP] [warmup=SECONDS]
*
* To run this in micro-benchmark mode, simply run as a normal java program.
* Be patient; this program runs for a very long time.
* For faster runs, restrict execution using command line args.
*
* @author Martin Buchholz
*/
public class IteratorMicroBenchmark {
abstract static class Job {
private final String name;
public Job(String name) { this.name = name; }
public String name() { return name; }
public abstract void work() throws Throwable;
}
static double warmupSeconds;
static long warmupNanos;
// --------------- GC finalization infrastructure ---------------
/** No guarantees, but effective in practice. */
static void forceFullGc() {
long timeoutMillis = 1000L;
CountDownLatch finalized = new CountDownLatch(1);
ReferenceQueue<Object> queue = new ReferenceQueue<>();
WeakReference<Object> ref = new WeakReference<>(
new Object() { protected void finalize() { finalized.countDown(); }},
queue);
try {
for (int tries = 3; tries--> 0; ) {
System.gc();
if (finalized.await(timeoutMillis, MILLISECONDS)
&& queue.remove(timeoutMillis) != null
&& ref.get() == null) {
System.runFinalization(); // try to pick up stragglers
return;
}
timeoutMillis *= 4;
}
} catch (InterruptedException unexpected) {
throw new AssertionError("unexpected InterruptedException");
}
throw new AssertionError("failed to do a \"full\" gc");
}
/**
* Runs each job for long enough that all the runtime compilers
* have had plenty of time to warm up, i.e. get around to
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
private static long[] time0(Job ... jobs) throws Throwable {
long[] nanoss = new long[jobs.length];
for (int i = 0; i < jobs.length; i++) {
if (warmupNanos > 0) forceFullGc();
Job job = jobs[i];
long totalTime;
int runs = 0;
long startTime = System.nanoTime();
do { job.work(); runs++; }
while ((totalTime = System.nanoTime() - startTime) < warmupNanos);
nanoss[i] = totalTime/runs;
}
return nanoss;
}
private static void time(Job ... jobs) throws Throwable {
if (warmupSeconds > 0.0) time0(jobs); // Warm up run
long[] nanoss = time0(jobs); // Real timing run
long[] milliss = new long[jobs.length];
double[] ratios = new double[jobs.length];
final String nameHeader = "Method";
final String millisHeader = "Millis";
final String ratioHeader = "Ratio";
int nameWidth = nameHeader.length();
int millisWidth = millisHeader.length();
int ratioWidth = ratioHeader.length();
for (int i = 0; i < jobs.length; i++) {
nameWidth = Math.max(nameWidth, jobs[i].name().length());
milliss[i] = nanoss[i]/(1000L * 1000L);
millisWidth = Math.max(millisWidth,
String.format("%d", milliss[i]).length());
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
ratioWidth = Math.max(ratioWidth,
String.format("%.3f", ratios[i]).length());
}
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
nameWidth, millisWidth, ratioWidth);
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
nameWidth, millisWidth, ratioWidth);
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
// Print out absolute and relative times, calibrated against first job
for (int i = 0; i < jobs.length; i++)
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
}
private static String keywordValue(String[] args, String keyword) {
for (String arg : args)
if (arg.startsWith(keyword))
return arg.substring(keyword.length() + 1);
return null;
}
private static int intArg(String[] args, String keyword, int defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Integer.parseInt(val);
}
private static double doubleArg(String[] args, String keyword, double defaultValue) {
String val = keywordValue(args, keyword);
return (val == null) ? defaultValue : Double.parseDouble(val);
}
private static Pattern patternArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
return (val == null) ? null : Pattern.compile(val);
}
private static Job[] filter(Pattern filter, Job[] jobs) {
return (filter == null) ? jobs
: Arrays.stream(jobs)
.filter(job -> filter.matcher(job.name()).find())
.collect(toList())
.toArray(new Job[0]);
}
private static void deoptimize(int sum) {
if (sum == 42)
System.out.println("the answer");
}
private static <T> List<T> asSubList(List<T> list) {
return list.subList(0, list.size());
}
private static <T> Iterable<T> backwards(final List<T> list) {
return new Iterable<T>() {
public Iterator<T> iterator() {
return new Iterator<T>() {
final ListIterator<T> it = list.listIterator(list.size());
public boolean hasNext() { return it.hasPrevious(); }
public T next() { return it.previous(); }
public void remove() { it.remove(); }};}};
}
public static void main(String[] args) throws Throwable {
final int iterations = intArg(args, "iterations", 100_000);
final int size = intArg(args, "size", 1000);
warmupSeconds = doubleArg(args, "warmup", 7.0);
final Pattern filter = patternArg(args, "filter");
warmupNanos = (long) (warmupSeconds * (1000L * 1000L * 1000L));
// System.out.printf(
// "iterations=%d size=%d, warmup=%1g, filter=\"%s\"%n",
// iterations, size, warmupSeconds, filter);
final ConcurrentSkipListMap<Integer,Integer> m
= new ConcurrentSkipListMap<>();
final ArrayList<Integer> al = new ArrayList<>(size);
// Populate collections with random data
final ThreadLocalRandom rnd = ThreadLocalRandom.current();
for (int i = 0; i < size; i++) {
m.put(rnd.nextInt(size), rnd.nextInt(size));
al.add(rnd.nextInt(size));
}
final Vector<Integer> v = new Vector<>(al);
final ArrayDeque<Integer> ad = new ArrayDeque<>(al);
// shuffle ArrayDeque elements so they wrap
for (int i = 0, n = rnd.nextInt(size); i < n; i++)
ad.addLast(ad.removeFirst());
// Also test "short" collections
final int shortSize = 5;
final Vector<Integer> sv = new Vector<>(v.subList(0, shortSize));
final ArrayList<Integer> sal = new ArrayList<>(sv);
// Checks for correctness *and* prevents loop optimizations
class Check {
private int sum;
public void sum(int sum) {
if (this.sum == 0)
this.sum = sum;
if (this.sum != sum)
throw new AssertionError("Sum mismatch");
}
}
final Check check = new Check();
final Check shortCheck = new Check();
Job[] jobs = {
// new Job("Vector iterate desugared") {
// public void work() throws Throwable {
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Iterator<Integer> it = v.iterator(); it.hasNext();)
// sum += it.next();
// check.sum(sum);}}},
new Job("array loop") {
public void work() throws Throwable {
Integer[] a = al.toArray(new Integer[0]);
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = a.length;
for (int j = 0; j < size; ++j)
sum += a[j];
check.sum(sum);}}},
new Job("descending array loop") {
public void work() throws Throwable {
Integer[] a = al.toArray(new Integer[0]);
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = a.length;
for (int j = size - 1; j >= 0; j--)
sum += a[j];
check.sum(sum);}}},
new Job("Vector get loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = v.size();
for (int j = 0; j < size; ++j)
sum += v.get(j);
check.sum(sum);}}},
new Job("Vector iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : v)
sum += n;
check.sum(sum);}}},
new Job("Vector descending listIterator loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = v.listIterator(al.size());
while (it.hasPrevious())
sum += it.previous();
check.sum(sum);}}},
new Job("Vector Enumeration loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Enumeration<Integer> it = v.elements();
while (it.hasMoreElements())
sum += it.nextElement();
check.sum(sum);}}},
new Job("Vector subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(v))
sum += n;
check.sum(sum);}}},
new Job("Vector subList subList subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(asSubList(asSubList(v))))
sum += n;
check.sum(sum);}}},
new Job("Vector backwards wrapper ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(v))
sum += n;
check.sum(sum);}}},
new Job("Vector backwards wrapper subList ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(asSubList(v)))
sum += n;
check.sum(sum);}}},
// new Job("Vector iterate for loop invokeinterface") {
// public void work() throws Throwable {
// final List<Integer> l = v;
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Integer n : l)
// sum += n;
// check.sum(sum);}}},
// new Job("Vector subList iterate for loop invokeinterface") {
// public void work() throws Throwable {
// final List<Integer> l = v;
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Integer n : asSubList(l))
// sum += n;
// check.sum(sum);}}},
new Job("Short Vector get loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
int size = sv.size();
for (int j = 0; j < size; ++j)
sum += sv.get(j);
shortCheck.sum(sum);}}},
new Job("Short Vector iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : sv)
sum += n;
shortCheck.sum(sum);}}},
new Job("Short Vector sublist iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : asSubList(sv))
sum += n;
shortCheck.sum(sum);}}},
new Job("ArrayList get loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = al.size();
for (int j = 0; j < size; ++j)
sum += al.get(j);
check.sum(sum);}}},
new Job("ArrayList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : al)
sum += n;
check.sum(sum);}}},
new Job("ArrayDeque iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : ad)
sum += n;
check.sum(sum);}}},
new Job("ArrayList descending listIterator loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = al.listIterator(al.size());
while (it.hasPrevious())
sum += it.previous();
check.sum(sum);}}},
new Job("ArrayList listIterator loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
ListIterator<Integer> it = al.listIterator();
while (it.hasNext())
sum += it.next();
check.sum(sum);}}},
new Job("ArrayDeque.descendingIterator() loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Iterator<Integer> it = ad.descendingIterator();
while (it.hasNext())
sum += it.next();
check.sum(sum);}}},
new Job("ArrayList.forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("Vector.forEach") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.forEach(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayList.iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.descendingIterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.descendingIterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("Vector.iterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.iterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayList.spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayDeque.spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("Vector.spliterator().forEachRemaining()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.spliterator().forEachRemaining(n -> sum[0] += n);
check.sum(sum[0]);}}},
new Job("ArrayList.spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = al.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job("ArrayDeque.spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = ad.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job("Vector.spliterator().tryAdvance()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
Spliterator<Integer> spliterator = v.spliterator();
do {} while (spliterator.tryAdvance(n -> sum[0] += n));
check.sum(sum[0]);}}},
new Job("ArrayList.removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("ArrayDeque.removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("Vector.removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("ArrayList subList .removeIf") {
public void work() throws Throwable {
int[] sum = new int[1];
List<Integer> sl = asSubList(al);
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
sl.removeIf(n -> { sum[0] += n; return false; });
check.sum(sum[0]);}}},
new Job("ArrayList subList get loop") {
public void work() throws Throwable {
List<Integer> sl = asSubList(al);
for (int i = 0; i < iterations; i++) {
int sum = 0;
int size = sl.size();
for (int j = 0; j < size; ++j)
sum += sl.get(j);
check.sum(sum);}}},
new Job("ArrayList subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(al))
sum += n;
check.sum(sum);}}},
new Job("ArrayList subList subList subList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : asSubList(asSubList(asSubList(al))))
sum += n;
check.sum(sum);}}},
new Job("ArrayList backwards wrapper ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(al))
sum += n;
check.sum(sum);}}},
new Job("ArrayList backwards wrapper subList ListIterator for loop") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Integer n : backwards(asSubList(al)))
sum += n;
check.sum(sum);}}},
// new Job("ArrayList iterate desugared") {
// public void work() throws Throwable {
// for (int i = 0; i < iterations; i++) {
// int sum = 0;
// for (Iterator<Integer> it = al.iterator(); it.hasNext();)
// sum += it.next();
// check.sum(sum);}}},
new Job("Short ArrayList get loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
int size = sal.size();
for (int j = 0; j < size; ++j)
sum += sal.get(j);
shortCheck.sum(sum);}}},
new Job("Short ArrayList iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : sal)
sum += n;
shortCheck.sum(sum);}}},
new Job("Short ArrayList sublist iterate for loop") {
public void work() throws Throwable {
for (int i = 0; i < (iterations * size / shortSize); i++) {
int sum = 0;
for (Integer n : asSubList(sal))
sum += n;
shortCheck.sum(sum);}}},
new Job("Vector ArrayList alternating iteration") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
Iterator<Integer> it1 = v.iterator();
Iterator<Integer> it2 = al.iterator();
while (it1.hasNext())
sum += it1.next() + it2.next();
check.sum(sum/2);}}},
new Job("Vector ArrayList alternating invokeVirtual iteration") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
List<Iterator<Integer>> its = new ArrayList<>(2);
its.add(v.iterator());
its.add(al.iterator());
for (int k = 0; its.get(k).hasNext(); k = (k == 0) ? 1 : 0)
sum += its.get(k).next();
check.sum(sum/2);}}},
new Job("ConcurrentSkipListMap entrySet iterate") {
public void work() throws Throwable {
for (int i = 0; i < iterations; i++) {
int sum = 0;
for (Map.Entry<Integer,Integer> e : m.entrySet())
sum += e.getKey();
deoptimize(sum);}}},
new Job("ArrayList.toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : al.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayList.toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
al.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayList subList .toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : asSubList(al).toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayList subList .toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
asSubList(al).toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayDeque.toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : ad.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("ArrayDeque.toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
ad.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("Vector.toArray()") {
public void work() throws Throwable {
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
for (Object o : v.toArray())
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
new Job("Vector.toArray(a)") {
public void work() throws Throwable {
Integer[] a = new Integer[size];
int[] sum = new int[1];
for (int i = 0; i < iterations; i++) {
sum[0] = 0;
v.toArray(a);
for (Object o : a)
sum[0] += (Integer) o;
check.sum(sum[0]);}}},
};
time(filter(filter, jobs));
}
}

View file

@ -0,0 +1,234 @@
/*
* Copyright (c) 2007, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* This is not a regression test, but a micro-benchmark.
*
* I have run this as follows:
*
* repeat 5 for f in -client -server; do mergeBench dolphin . jr -dsa -da $f RangeCheckMicroBenchmark.java; done
*
*
* @author Martin Buchholz
*/
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Pattern;
import static java.util.stream.Collectors.toList;
public class RangeCheckMicroBenchmark {
abstract static class Job {
private final String name;
Job(String name) { this.name = name; }
String name() { return name; }
abstract void work() throws Throwable;
}
private static void collectAllGarbage() {
final CountDownLatch drained = new CountDownLatch(1);
try {
System.gc(); // enqueue finalizable objects
new Object() { protected void finalize() {
drained.countDown(); }};
System.gc(); // enqueue detector
drained.await(); // wait for finalizer queue to drain
System.gc(); // cleanup finalized objects
} catch (InterruptedException e) { throw new Error(e); }
}
/**
* Runs each job for long enough that all the runtime compilers
* have had plenty of time to warm up, i.e. get around to
* compiling everything worth compiling.
* Returns array of average times per job per run.
*/
private static long[] time0(Job ... jobs) throws Throwable {
final long warmupNanos = 10L * 1000L * 1000L * 1000L;
long[] nanoss = new long[jobs.length];
for (int i = 0; i < jobs.length; i++) {
collectAllGarbage();
long t0 = System.nanoTime();
long t;
int j = 0;
do { jobs[i].work(); j++; }
while ((t = System.nanoTime() - t0) < warmupNanos);
nanoss[i] = t/j;
}
return nanoss;
}
private static void time(Job ... jobs) throws Throwable {
long[] warmup = time0(jobs); // Warm up run
long[] nanoss = time0(jobs); // Real timing run
long[] milliss = new long[jobs.length];
double[] ratios = new double[jobs.length];
final String nameHeader = "Method";
final String millisHeader = "Millis";
final String ratioHeader = "Ratio";
int nameWidth = nameHeader.length();
int millisWidth = millisHeader.length();
int ratioWidth = ratioHeader.length();
for (int i = 0; i < jobs.length; i++) {
nameWidth = Math.max(nameWidth, jobs[i].name().length());
milliss[i] = nanoss[i]/(1000L * 1000L);
millisWidth = Math.max(millisWidth,
String.format("%d", milliss[i]).length());
ratios[i] = (double) nanoss[i] / (double) nanoss[0];
ratioWidth = Math.max(ratioWidth,
String.format("%.3f", ratios[i]).length());
}
String format = String.format("%%-%ds %%%dd %%%d.3f%%n",
nameWidth, millisWidth, ratioWidth);
String headerFormat = String.format("%%-%ds %%%ds %%%ds%%n",
nameWidth, millisWidth, ratioWidth);
System.out.printf(headerFormat, "Method", "Millis", "Ratio");
// Print out absolute and relative times, calibrated against first job
for (int i = 0; i < jobs.length; i++)
System.out.printf(format, jobs[i].name(), milliss[i], ratios[i]);
}
private static String keywordValue(String[] args, String keyword) {
for (String arg : args)
if (arg.startsWith(keyword))
return arg.substring(keyword.length() + 1);
return null;
}
private static int intArg(String[] args, String keyword, int defaultValue) {
String val = keywordValue(args, keyword);
return val == null ? defaultValue : Integer.parseInt(val);
}
private static Pattern patternArg(String[] args, String keyword) {
String val = keywordValue(args, keyword);
return val == null ? null : Pattern.compile(val);
}
private static Job[] filter(Pattern filter, Job[] jobs) {
return (filter == null) ? jobs
: Arrays.stream(jobs)
.filter(job -> filter.matcher(job.name()).find())
.collect(toList())
.toArray(new Job[0]);
}
private static void deoptimize(ArrayList<Integer> list) {
for (Integer x : list)
if (x == null)
throw new Error();
}
/**
* Usage: [iterations=N] [size=N] [filter=REGEXP]
*/
public static void main(String[] args) throws Throwable {
final int iterations = intArg(args, "iterations", 30000);
final int size = intArg(args, "size", 1000);
final Pattern filter = patternArg(args, "filter");
final ArrayList<Integer> list = new ArrayList<>();
final Random rnd = new Random();
for (int i = 0; i < size; i++)
list.add(rnd.nextInt());
final Job[] jobs = {
new Job("get") { void work() {
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
if (list.get(k) == 42)
throw new Error();
}
deoptimize(list);}},
new Job("set") { void work() {
Integer[] xs = list.toArray(new Integer[size]);
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
list.set(k, xs[k]);
}
deoptimize(list);}},
new Job("get/set") { void work() {
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
list.set(k, list.get(size - k - 1));
}
deoptimize(list);}},
new Job("add/remove at end") { void work() {
Integer x = rnd.nextInt();
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size - 1; k++) {
list.add(size, x);
list.remove(size);
}
}
deoptimize(list);}},
new Job("subList get") { void work() {
List<Integer> sublist = list.subList(0, list.size());
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
if (sublist.get(k) == 42)
throw new Error();
}
deoptimize(list);}},
new Job("subList set") { void work() {
List<Integer> sublist = list.subList(0, list.size());
Integer[] xs = sublist.toArray(new Integer[size]);
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
sublist.set(k, xs[k]);
}
deoptimize(list);}},
new Job("subList get/set") { void work() {
List<Integer> sublist = list.subList(0, list.size());
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size; k++)
sublist.set(k, sublist.get(size - k - 1));
}
deoptimize(list);}},
new Job("subList add/remove at end") { void work() {
List<Integer> sublist = list.subList(0, list.size());
Integer x = rnd.nextInt();
for (int i = 0; i < iterations; i++) {
for (int k = 0; k < size - 1; k++) {
sublist.add(size, x);
sublist.remove(size);
}
}
deoptimize(list);}}
};
time(filter(filter, jobs));
}
}

View file

@ -0,0 +1,59 @@
/*
* Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.ConcurrentModificationException;
import java.util.List;
/**
* @test
* @bug 8340572
* @summary ConcurrentModificationException when sorting ArrayList sublists
*/
public class SortingModCount {
public static void main(String[] args) {
testSortingSubListsDoesNotIncrementModCount();
testSortingListDoesIncrementModCount();
}
private static void testSortingSubListsDoesNotIncrementModCount() {
List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
var a = l.subList(0, 2);
var b = l.subList(2, 4);
Collections.sort(a);
Collections.sort(b);
}
private static void testSortingListDoesIncrementModCount() {
List<Integer> l = new ArrayList<>(List.of(1, 2, 3, 4));
var b = l.subList(2, 4);
Collections.sort(l);
try {
Collections.sort(b);
throw new Error("expected ConcurrentModificationException not thrown");
} catch (ConcurrentModificationException expected) {
}
}
}

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* @test
* @bug 8234423
* @summary Modifying ArrayList.subList().subList() resets modCount of subList
*/
import java.util.ArrayList;
import java.util.ConcurrentModificationException;
public class SubListModCount {
public static void main(String[] args) {
int failures = 0;
var root = new ArrayList<Integer>();
var subList = root.subList(0, 0);
root.add(42);
try {
subList.size();
failures++;
System.out.println("Accessing subList");
} catch (ConcurrentModificationException expected) {
}
var subSubList = subList.subList(0, 0);
try {
subSubList.size();
failures++;
System.out.println("Accessing subList.subList");
} catch (ConcurrentModificationException expected) {
}
try {
subSubList.add(42);
failures++;
System.out.println("Modifying subList.subList");
} catch (ConcurrentModificationException expected) {
}
try {
subList.size();
failures++;
System.out.println("Accessing subList again");
} catch (ConcurrentModificationException expected) {
}
if (failures > 0) {
throw new AssertionError(failures + " tests failed");
}
}
}