8174109: Better queuing priorities
Reviewed-by: chegar, dfuchs, rriggs, alanb, robm, rhalade, jeff, ahgross
--- a/src/java.base/share/classes/java/io/ObjectInputStream.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/io/ObjectInputStream.java Wed Aug 02 10:34:35 2017 -0700
@@ -1283,6 +1283,33 @@
}
/**
+ * Checks the given array type and length to ensure that creation of such
+ * an array is permitted by this ObjectInputStream. The arrayType argument
+ * must represent an actual array type.
+ *
+ * This private method is called via SharedSecrets.
+ *
+ * @param arrayType the array type
+ * @param arrayLength the array length
+ * @throws NullPointerException if arrayType is null
+ * @throws IllegalArgumentException if arrayType isn't actually an array type
+ * @throws NegativeArraySizeException if arrayLength is negative
+ * @throws InvalidClassException if the filter rejects creation
+ */
+ private void checkArray(Class<?> arrayType, int arrayLength) throws InvalidClassException {
+ Objects.requireNonNull(arrayType);
+ if (! arrayType.isArray()) {
+ throw new IllegalArgumentException("not an array type");
+ }
+
+ if (arrayLength < 0) {
+ throw new NegativeArraySizeException();
+ }
+
+ filterCheck(arrayType, arrayLength);
+ }
+
+ /**
* Provide access to the persistent fields read from the input stream.
*/
public abstract static class GetField {
@@ -3982,6 +4009,10 @@
}
}
+ static {
+ SharedSecrets.setJavaObjectInputStreamAccess(ObjectInputStream::checkArray);
+ }
+
private void validateDescriptor(ObjectStreamClass descriptor) {
ObjectStreamClassValidator validating = validator;
if (validating != null) {
--- a/src/java.base/share/classes/java/util/ArrayDeque.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/ArrayDeque.java Wed Aug 02 10:34:35 2017 -0700
@@ -38,6 +38,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.misc.SharedSecrets;
/**
* Resizable-array implementation of the {@link Deque} interface. Array
@@ -1194,6 +1195,7 @@
// Read in size and allocate array
int size = s.readInt();
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size + 1);
elements = new Object[size + 1];
this.tail = size;
--- a/src/java.base/share/classes/java/util/ArrayList.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/ArrayList.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -28,6 +28,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.misc.SharedSecrets;
/**
* Resizable-array implementation of the {@code List} interface. Implements
@@ -814,6 +815,7 @@
if (size > 0) {
// like clone(), allocate array based upon size not capacity
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
Object[] elements = new Object[size];
// Read in all elements in the proper order.
--- a/src/java.base/share/classes/java/util/HashMap.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/HashMap.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -34,6 +34,7 @@
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
+import jdk.internal.misc.SharedSecrets;
/**
* Hash table based implementation of the {@code Map} interface. This
@@ -1448,6 +1449,10 @@
float ft = (float)cap * lf;
threshold = ((cap < MAXIMUM_CAPACITY && ft < MAXIMUM_CAPACITY) ?
(int)ft : Integer.MAX_VALUE);
+
+ // Check Map.Entry[].class since it's the nearest public type to
+ // what we're actually creating.
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, cap);
@SuppressWarnings({"rawtypes","unchecked"})
Node<K,V>[] tab = (Node<K,V>[])new Node[cap];
table = tab;
--- a/src/java.base/share/classes/java/util/HashSet.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/HashSet.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, 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
@@ -26,6 +26,7 @@
package java.util;
import java.io.InvalidObjectException;
+import jdk.internal.misc.SharedSecrets;
/**
* This class implements the {@code Set} interface, backed by a hash table
@@ -322,6 +323,13 @@
capacity = (int) Math.min(size * Math.min(1 / loadFactor, 4.0f),
HashMap.MAXIMUM_CAPACITY);
+ // Constructing the backing map will lazily create an array when the first element is
+ // added, so check it before construction. Call HashMap.tableSizeFor to compute the
+ // actual allocation size. Check Map.Entry[].class since it's the nearest public type to
+ // what is actually created.
+ SharedSecrets.getJavaObjectInputStreamAccess()
+ .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor(capacity));
+
// Create backing HashMap
map = (((HashSet<?>)this) instanceof LinkedHashSet ?
new LinkedHashMap<>(capacity, loadFactor) :
--- a/src/java.base/share/classes/java/util/Hashtable.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/Hashtable.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 1994, 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1994, 2017, 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
@@ -29,6 +29,7 @@
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.function.BiFunction;
+import jdk.internal.misc.SharedSecrets;
/**
* This class implements a hash table, which maps keys to values. Any
@@ -1291,6 +1292,10 @@
if (length > elements && (length & 1) == 0)
length--;
length = Math.min(length, origlength);
+
+ // Check Map.Entry[].class since it's the nearest public type to
+ // what we're actually creating.
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Map.Entry[].class, length);
table = new Entry<?,?>[length];
threshold = (int)Math.min(length * loadFactor, MAX_ARRAY_SIZE + 1);
count = 0;
--- a/src/java.base/share/classes/java/util/IdentityHashMap.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/IdentityHashMap.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, 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
@@ -29,6 +29,7 @@
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
+import jdk.internal.misc.SharedSecrets;
/**
* This class implements the {@code Map} interface with a hash table, using
@@ -1304,7 +1305,9 @@
if (size < 0)
throw new java.io.StreamCorruptedException
("Illegal mappings count: " + size);
- init(capacity(size));
+ int cap = capacity(size);
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, cap);
+ init(cap);
// Read the keys and values, and put the mappings in the table
for (int i=0; i<size; i++) {
--- a/src/java.base/share/classes/java/util/ImmutableCollections.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/ImmutableCollections.java Wed Aug 02 10:34:35 2017 -0700
@@ -35,6 +35,7 @@
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.misc.SharedSecrets;
import jdk.internal.vm.annotation.Stable;
/**
@@ -885,6 +886,7 @@
throw new InvalidObjectException("negative length " + len);
}
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(ois, Object[].class, len);
Object[] a = new Object[len];
for (int i = 0; i < len; i++) {
a[i] = ois.readObject();
--- a/src/java.base/share/classes/java/util/PriorityQueue.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/PriorityQueue.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2017, 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
@@ -26,6 +26,7 @@
package java.util;
import java.util.function.Consumer;
+import jdk.internal.misc.SharedSecrets;
/**
* An unbounded priority {@linkplain Queue queue} based on a priority heap.
@@ -795,6 +796,7 @@
// Read in (and discard) array length
s.readInt();
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, size);
queue = new Object[size];
// Read in all elements.
--- a/src/java.base/share/classes/java/util/Properties.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/Properties.java Wed Aug 02 10:34:35 2017 -0700
@@ -42,6 +42,7 @@
import java.util.function.BiFunction;
import java.util.function.Function;
+import jdk.internal.misc.SharedSecrets;
import jdk.internal.util.xml.PropertiesDefaultHandler;
/**
@@ -1441,6 +1442,16 @@
throw new StreamCorruptedException("Illegal # of Elements: " + elements);
}
+ // Constructing the backing map will lazily create an array when the first element is
+ // added, so check it before construction. Note that CHM's constructor takes a size
+ // that is the number of elements to be stored -- not the table size -- so it must be
+ // inflated by the default load factor of 0.75, then inflated to the next power of two.
+ // (CHM uses the same power-of-two computation as HashMap, and HashMap.tableSizeFor is
+ // accessible here.) Check Map.Entry[].class since it's the nearest public type to
+ // what is actually created.
+ SharedSecrets.getJavaObjectInputStreamAccess()
+ .checkArray(s, Map.Entry[].class, HashMap.tableSizeFor((int)(elements / 0.75)));
+
// create CHM of appropriate capacity
map = new ConcurrentHashMap<>(elements);
--- a/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/java/util/concurrent/CopyOnWriteArrayList.java Wed Aug 02 10:34:35 2017 -0700
@@ -51,6 +51,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
+import jdk.internal.misc.SharedSecrets;
/**
* A thread-safe variant of {@link java.util.ArrayList} in which all mutative
@@ -933,6 +934,7 @@
// Read in array length and allocate array
int len = s.readInt();
+ SharedSecrets.getJavaObjectInputStreamAccess().checkArray(s, Object[].class, len);
Object[] elements = new Object[len];
// Read in all elements in the proper order.
--- a/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java Wed Jul 26 17:44:06 2017 +0100
+++ b/src/java.base/share/classes/jdk/internal/misc/JavaObjectInputStreamAccess.java Wed Aug 02 10:34:35 2017 -0700
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 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
@@ -25,17 +25,14 @@
package jdk.internal.misc;
+import java.io.InvalidClassException;
import java.io.ObjectInputStream;
/**
- * The interface to specify methods for accessing {@code ObjectInputStream}
- * @author sjiang
+ * Interface to specify methods for accessing {@code ObjectInputStream}.
*/
+@FunctionalInterface
public interface JavaObjectInputStreamAccess {
- /**
- * Sets a descriptor validating.
- * @param ois stream to have the descriptors validated
- * @param validator validator used to validate a descriptor.
- */
- public void setValidator(ObjectInputStream ois, ObjectStreamClassValidator validator);
+ void checkArray(ObjectInputStream ois, Class<?> arrayType, int arrayLength)
+ throws InvalidClassException;
}
--- a/src/java.base/share/classes/jdk/internal/misc/ObjectStreamClassValidator.java Wed Jul 26 17:44:06 2017 +0100
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2016, 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. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the LICENSE file that accompanied this code.
- *
- * 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.
- */
-package jdk.internal.misc;
-
-import java.io.ObjectStreamClass;
-
-/**
- * A callback used by {@code ObjectInputStream} to do descriptor validation.
- *
- * @author sjiang
- */
-public interface ObjectStreamClassValidator {
- /**
- * This method will be called by ObjectInputStream to
- * check a descriptor just before creating an object described by this descriptor.
- * The object will not be created if this method throws a {@code RuntimeException}.
- * @param descriptor descriptor to be checked.
- */
- public void validateDescriptor(ObjectStreamClass descriptor);
-}
--- a/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java Wed Jul 26 17:44:06 2017 +0100
+++ b/test/jdk/java/io/Serializable/serialFilter/SerialFilterTest.java Wed Aug 02 10:34:35 2017 -0700
@@ -36,9 +36,11 @@
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.atomic.LongAdder;
import javax.net.ssl.SSLEngineResult;
@@ -165,6 +167,11 @@
interfaces, (p, m, args) -> p);
Runnable runnable = (Runnable & Serializable) SerialFilterTest::noop;
+
+ List<Class<?>> classList = new ArrayList<>();
+ classList.add(HashSet.class);
+ classList.addAll(Collections.nCopies(21, Map.Entry[].class));
+
Object[][] objects = {
{ null, 0, -1, 0, 0, 0,
Arrays.asList()}, // no callback, no values
@@ -184,8 +191,7 @@
objArray.getClass(),
SerialFilterTest.class,
java.lang.invoke.SerializedLambda.class)},
- { deepHashSet(10), 48, -1, 50, 11, 619,
- Arrays.asList(HashSet.class)},
+ { deepHashSet(10), 69, 4, 50, 11, 619, classList },
{ proxy.getClass(), 3, -1, 2, 2, 112,
Arrays.asList(Runnable.class,
java.lang.reflect.Proxy.class,