# HG changeset patch # User darcy # Date 1553807937 25200 # Node ID ce3598fceb879eb6661f7c75d77ada5f3ed65545 # Parent 2b0acaf92eccfbd0de4cafdfa0a9c48889038f46 8212328: Exceptional throw cases Reviewed-by: smarks, rriggs, igerasim, ahgross, skoivu diff -r 2b0acaf92ecc -r ce3598fceb87 src/java.base/share/classes/java/lang/Throwable.java --- a/src/java.base/share/classes/java/lang/Throwable.java Wed Mar 27 00:24:13 2019 -0700 +++ b/src/java.base/share/classes/java/lang/Throwable.java Thu Mar 28 14:18:57 2019 -0700 @@ -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 @@ private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); // read in all fields - if (suppressedExceptions != null) { - List 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 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(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 @@ * 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 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; } }