8212328: Exceptional throw cases

Reviewed-by: smarks, rriggs, igerasim, ahgross, skoivu
This commit is contained in:
Joe Darcy 2019-03-28 14:18:57 -07:00
parent 27e83c186a
commit 12802b7e8d

View file

@ -25,8 +25,8 @@
package java.lang;
import java.io.*;
import java.util.*;
import java.io.*;
import java.util.*;
/**
* The {@code Throwable} class is the superclass of all errors and
@ -904,24 +904,36 @@ public class Throwable implements Serializable {
private void readObject(ObjectInputStream s)
throws IOException, ClassNotFoundException {
s.defaultReadObject(); // read in all fields
if (suppressedExceptions != null) {
List<Throwable> suppressed = null;
if (suppressedExceptions.isEmpty()) {
// Use the sentinel for a zero-length list
suppressed = SUPPRESSED_SENTINEL;
} else { // Copy Throwables to new list
suppressed = new ArrayList<>(1);
for (Throwable t : suppressedExceptions) {
// Set suppressed exceptions and stack trace elements fields
// to marker values until the contents from the serial stream
// are validated.
List<Throwable> candidateSuppressedExceptions = suppressedExceptions;
suppressedExceptions = SUPPRESSED_SENTINEL;
StackTraceElement[] candidateStackTrace = stackTrace;
stackTrace = UNASSIGNED_STACK.clone();
if (candidateSuppressedExceptions != null) {
int suppressedSize = validateSuppressedExceptionsList(candidateSuppressedExceptions);
if (suppressedSize > 0) { // Copy valid Throwables to new list
var suppList = new ArrayList<Throwable>(Math.min(100, suppressedSize));
for (Throwable t : candidateSuppressedExceptions) {
// Enforce constraints on suppressed exceptions in
// case of corrupt or malicious stream.
Objects.requireNonNull(t, NULL_CAUSE_MESSAGE);
if (t == this)
throw new IllegalArgumentException(SELF_SUPPRESSION_MESSAGE);
suppressed.add(t);
suppList.add(t);
}
// If there are any invalid suppressed exceptions,
// implicitly use the sentinel value assigned earlier.
suppressedExceptions = suppList;
}
suppressedExceptions = suppressed;
} // else a null suppressedExceptions field remains null
} else {
suppressedExceptions = null;
}
/*
* For zero-length stack traces, use a clone of
@ -932,24 +944,41 @@ public class Throwable implements Serializable {
* the stackTrace needs to be constructed from the information
* in backtrace.
*/
if (stackTrace != null) {
if (stackTrace.length == 0) {
stackTrace = UNASSIGNED_STACK.clone();
} else if (stackTrace.length == 1 &&
if (candidateStackTrace != null) {
// Work from a clone of the candidateStackTrace to ensure
// consistency of checks.
candidateStackTrace = candidateStackTrace.clone();
if (candidateStackTrace.length >= 1) {
if (candidateStackTrace.length == 1 &&
// Check for the marker of an immutable stack trace
SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(stackTrace[0])) {
stackTrace = null;
} else { // Verify stack trace elements are non-null.
for(StackTraceElement ste : stackTrace) {
Objects.requireNonNull(ste, "null StackTraceElement in serial stream.");
SentinelHolder.STACK_TRACE_ELEMENT_SENTINEL.equals(candidateStackTrace[0])) {
stackTrace = null;
} else { // Verify stack trace elements are non-null.
for (StackTraceElement ste : candidateStackTrace) {
Objects.requireNonNull(ste, "null StackTraceElement in serial stream.");
}
stackTrace = candidateStackTrace;
}
}
}
// A null stackTrace field in the serial form can result from
// an exception serialized without that field in older JDK
// releases; treat such exceptions as having empty stack
// traces by leaving stackTrace assigned to a clone of
// UNASSIGNED_STACK.
}
private int validateSuppressedExceptionsList(List<Throwable> deserSuppressedExceptions)
throws IOException {
if (!Object.class.getModule().
equals(deserSuppressedExceptions.getClass().getModule())) {
throw new StreamCorruptedException("List implementation not in base module.");
} else {
// A null stackTrace field in the serial form can result
// from an exception serialized without that field in
// older JDK releases; treat such exceptions as having
// empty stack traces.
stackTrace = UNASSIGNED_STACK.clone();
int size = deserSuppressedExceptions.size();
if (size < 0) {
throw new StreamCorruptedException("Negative list size reported.");
}
return size;
}
}