8230744: Several classes throw OutOfMemoryError without message
Reviewed-by: psandoz, martin, bchristi, rriggs, smarks
This commit is contained in:
parent
2085fd32ff
commit
03642a01af
@ -31,6 +31,7 @@ import java.util.Arrays;
|
|||||||
import java.util.Spliterator;
|
import java.util.Spliterator;
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
import java.util.stream.StreamSupport;
|
import java.util.stream.StreamSupport;
|
||||||
|
import jdk.internal.util.ArraysSupport;
|
||||||
|
|
||||||
import static java.lang.String.COMPACT_STRINGS;
|
import static java.lang.String.COMPACT_STRINGS;
|
||||||
import static java.lang.String.UTF16;
|
import static java.lang.String.UTF16;
|
||||||
@ -239,7 +240,7 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a capacity at least as large as the given minimum capacity.
|
* Returns a capacity at least as large as the given minimum capacity.
|
||||||
* Returns the current capacity increased by the same amount + 2 if
|
* Returns the current capacity increased by the current length + 2 if
|
||||||
* that suffices.
|
* that suffices.
|
||||||
* Will not return a capacity greater than
|
* Will not return a capacity greater than
|
||||||
* {@code (MAX_ARRAY_SIZE >> coder)} unless the given minimum capacity
|
* {@code (MAX_ARRAY_SIZE >> coder)} unless the given minimum capacity
|
||||||
@ -250,26 +251,14 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
|
|||||||
* greater than (Integer.MAX_VALUE >> coder)
|
* greater than (Integer.MAX_VALUE >> coder)
|
||||||
*/
|
*/
|
||||||
private int newCapacity(int minCapacity) {
|
private int newCapacity(int minCapacity) {
|
||||||
// overflow-conscious code
|
int oldLength = value.length;
|
||||||
int oldCapacity = value.length >> coder;
|
int newLength = minCapacity << coder;
|
||||||
int newCapacity = (oldCapacity << 1) + 2;
|
int growth = newLength - oldLength;
|
||||||
if (newCapacity - minCapacity < 0) {
|
int length = ArraysSupport.newLength(oldLength, growth, oldLength + (2 << coder));
|
||||||
newCapacity = minCapacity;
|
if (length == Integer.MAX_VALUE) {
|
||||||
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
|
return length >> coder;
|
||||||
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
|
|
||||||
? hugeCapacity(minCapacity)
|
|
||||||
: newCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int hugeCapacity(int minCapacity) {
|
|
||||||
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
|
|
||||||
int UNSAFE_BOUND = Integer.MAX_VALUE >> coder;
|
|
||||||
if (UNSAFE_BOUND - minCapacity < 0) { // overflow
|
|
||||||
throw new OutOfMemoryError();
|
|
||||||
}
|
|
||||||
return (minCapacity > SAFE_BOUND)
|
|
||||||
? minCapacity : SAFE_BOUND;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2187,7 +2187,7 @@ public final class String
|
|||||||
resultLen = Math.addExact(thisLen, Math.multiplyExact(
|
resultLen = Math.addExact(thisLen, Math.multiplyExact(
|
||||||
Math.addExact(thisLen, 1), replLen));
|
Math.addExact(thisLen, 1), replLen));
|
||||||
} catch (ArithmeticException ignored) {
|
} catch (ArithmeticException ignored) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
|
|
||||||
StringBuilder sb = new StringBuilder(resultLen);
|
StringBuilder sb = new StringBuilder(resultLen);
|
||||||
@ -3571,15 +3571,14 @@ public final class String
|
|||||||
if (len == 0 || count == 0) {
|
if (len == 0 || count == 0) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
if (Integer.MAX_VALUE / count < len) {
|
||||||
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
|
}
|
||||||
if (len == 1) {
|
if (len == 1) {
|
||||||
final byte[] single = new byte[count];
|
final byte[] single = new byte[count];
|
||||||
Arrays.fill(single, value[0]);
|
Arrays.fill(single, value[0]);
|
||||||
return new String(single, coder);
|
return new String(single, coder);
|
||||||
}
|
}
|
||||||
if (Integer.MAX_VALUE / count < len) {
|
|
||||||
throw new OutOfMemoryError("Repeating " + len + " bytes String " + count +
|
|
||||||
" times will produce a String exceeding maximum size.");
|
|
||||||
}
|
|
||||||
final int limit = len * count;
|
final int limit = len * count;
|
||||||
final byte[] multiple = new byte[limit];
|
final byte[] multiple = new byte[limit];
|
||||||
System.arraycopy(value, 0, multiple, 0, len);
|
System.arraycopy(value, 0, multiple, 0, len);
|
||||||
|
@ -357,7 +357,7 @@ final class StringLatin1 {
|
|||||||
resultLen = Math.addExact(valLen,
|
resultLen = Math.addExact(valLen,
|
||||||
Math.multiplyExact(++p, replLen - targLen));
|
Math.multiplyExact(++p, replLen - targLen));
|
||||||
} catch (ArithmeticException ignored) {
|
} catch (ArithmeticException ignored) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
if (resultLen == 0) {
|
if (resultLen == 0) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -661,7 +661,7 @@ final class StringUTF16 {
|
|||||||
resultLen = Math.addExact(valLen,
|
resultLen = Math.addExact(valLen,
|
||||||
Math.multiplyExact(++p, replLen - targLen));
|
Math.multiplyExact(++p, replLen - targLen));
|
||||||
} catch (ArithmeticException ignored) {
|
} catch (ArithmeticException ignored) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
if (resultLen == 0) {
|
if (resultLen == 0) {
|
||||||
return "";
|
return "";
|
||||||
|
@ -53,6 +53,7 @@ import java.util.concurrent.locks.ReentrantLock;
|
|||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import jdk.internal.access.SharedSecrets;
|
import jdk.internal.access.SharedSecrets;
|
||||||
|
import jdk.internal.util.ArraysSupport;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unbounded {@linkplain BlockingQueue blocking queue} that uses
|
* An unbounded {@linkplain BlockingQueue blocking queue} that uses
|
||||||
@ -136,14 +137,6 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
|||||||
*/
|
*/
|
||||||
private static final int DEFAULT_INITIAL_CAPACITY = 11;
|
private static final int DEFAULT_INITIAL_CAPACITY = 11;
|
||||||
|
|
||||||
/**
|
|
||||||
* The maximum size of array to allocate.
|
|
||||||
* Some VMs reserve some header words in an array.
|
|
||||||
* Attempts to allocate larger arrays may result in
|
|
||||||
* OutOfMemoryError: Requested array size exceeds VM limit
|
|
||||||
*/
|
|
||||||
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Priority queue represented as a balanced binary heap: the two
|
* Priority queue represented as a balanced binary heap: the two
|
||||||
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
|
* children of queue[n] are queue[2*n+1] and queue[2*(n+1)]. The
|
||||||
@ -298,16 +291,9 @@ public class PriorityBlockingQueue<E> extends AbstractQueue<E>
|
|||||||
if (allocationSpinLock == 0 &&
|
if (allocationSpinLock == 0 &&
|
||||||
ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
|
ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
|
||||||
try {
|
try {
|
||||||
int newCap = oldCap + ((oldCap < 64) ?
|
int growth = oldCap < 64 ? oldCap + 2 : oldCap >> 1;
|
||||||
(oldCap + 2) : // grow faster if small
|
int newCap = ArraysSupport.newLength(oldCap, 1, growth);
|
||||||
(oldCap >> 1));
|
if (queue == array)
|
||||||
if (newCap - MAX_ARRAY_SIZE > 0) { // possible overflow
|
|
||||||
int minCap = oldCap + 1;
|
|
||||||
if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
|
|
||||||
throw new OutOfMemoryError();
|
|
||||||
newCap = MAX_ARRAY_SIZE;
|
|
||||||
}
|
|
||||||
if (newCap > oldCap && queue == array)
|
|
||||||
newArray = new Object[newCap];
|
newArray = new Object[newCap];
|
||||||
} finally {
|
} finally {
|
||||||
allocationSpinLock = 0;
|
allocationSpinLock = 0;
|
||||||
|
@ -1681,7 +1681,7 @@ loop: for(int x=0, offset=0; x<nCodePoints; x++, offset+=len) {
|
|||||||
try {
|
try {
|
||||||
newTempLen = Math.addExact(j + 2, Math.multiplyExact(3, pLen - i));
|
newTempLen = Math.addExact(j + 2, Math.multiplyExact(3, pLen - i));
|
||||||
} catch (ArithmeticException ae) {
|
} catch (ArithmeticException ae) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required pattern length too large");
|
||||||
}
|
}
|
||||||
int[] newtemp = new int[newTempLen];
|
int[] newtemp = new int[newTempLen];
|
||||||
System.arraycopy(temp, 0, newtemp, 0, j);
|
System.arraycopy(temp, 0, newtemp, 0, j);
|
||||||
|
@ -629,7 +629,7 @@ public final class Unsafe {
|
|||||||
|
|
||||||
long p = allocateMemory0(bytes);
|
long p = allocateMemory0(bytes);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Unable to allocate " + bytes + " bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
@ -685,7 +685,7 @@ public final class Unsafe {
|
|||||||
|
|
||||||
long p = (address == 0) ? allocateMemory0(bytes) : reallocateMemory0(address, bytes);
|
long p = (address == 0) ? allocateMemory0(bytes) : reallocateMemory0(address, bytes);
|
||||||
if (p == 0) {
|
if (p == 0) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Unable to allocate " + bytes + " bytes");
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
|
@ -46,7 +46,7 @@ public class UnsyncByteArrayOutputStream extends OutputStream {
|
|||||||
|
|
||||||
public void write(byte[] arg0) {
|
public void write(byte[] arg0) {
|
||||||
if ((VM_ARRAY_INDEX_MAX_VALUE - pos) < arg0.length) {
|
if ((VM_ARRAY_INDEX_MAX_VALUE - pos) < arg0.length) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
int newPos = pos + arg0.length;
|
int newPos = pos + arg0.length;
|
||||||
if (newPos > size) {
|
if (newPos > size) {
|
||||||
@ -58,7 +58,7 @@ public class UnsyncByteArrayOutputStream extends OutputStream {
|
|||||||
|
|
||||||
public void write(byte[] arg0, int arg1, int arg2) {
|
public void write(byte[] arg0, int arg1, int arg2) {
|
||||||
if ((VM_ARRAY_INDEX_MAX_VALUE - pos) < arg2) {
|
if ((VM_ARRAY_INDEX_MAX_VALUE - pos) < arg2) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
int newPos = pos + arg2;
|
int newPos = pos + arg2;
|
||||||
if (newPos > size) {
|
if (newPos > size) {
|
||||||
@ -70,7 +70,7 @@ public class UnsyncByteArrayOutputStream extends OutputStream {
|
|||||||
|
|
||||||
public void write(int arg0) {
|
public void write(int arg0) {
|
||||||
if (VM_ARRAY_INDEX_MAX_VALUE - pos == 0) {
|
if (VM_ARRAY_INDEX_MAX_VALUE - pos == 0) {
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
}
|
}
|
||||||
int newPos = pos + 1;
|
int newPos = pos + 1;
|
||||||
if (newPos > size) {
|
if (newPos > size) {
|
||||||
|
@ -244,7 +244,7 @@ public class ByteArrayChannel implements SeekableByteChannel {
|
|||||||
|
|
||||||
private static int hugeCapacity(int minCapacity) {
|
private static int hugeCapacity(int minCapacity) {
|
||||||
if (minCapacity < 0) // overflow
|
if (minCapacity < 0) // overflow
|
||||||
throw new OutOfMemoryError();
|
throw new OutOfMemoryError("Required length exceeds implementation limit");
|
||||||
return (minCapacity > MAX_ARRAY_SIZE) ?
|
return (minCapacity > MAX_ARRAY_SIZE) ?
|
||||||
Integer.MAX_VALUE :
|
Integer.MAX_VALUE :
|
||||||
MAX_ARRAY_SIZE;
|
MAX_ARRAY_SIZE;
|
||||||
|
Loading…
Reference in New Issue
Block a user