6973831: NPE when printing stack trace of OOME
authormchung
Thu, 12 Aug 2010 16:36:49 -0700
changeset 6302 ec168532bf3f
parent 6300 700ec2a5d680
child 6303 a9a370fe0932
6973831: NPE when printing stack trace of OOME Summary: Initialize suppressedExceptions field to null Reviewed-by: briangoetz, dholmes, forax
jdk/src/share/classes/java/lang/Throwable.java
--- a/jdk/src/share/classes/java/lang/Throwable.java	Tue Aug 10 13:15:40 2010 -0700
+++ b/jdk/src/share/classes/java/lang/Throwable.java	Thu Aug 12 16:36:49 2010 -0700
@@ -200,7 +200,16 @@
      * @serial
      * @since 1.7
      */
-    private List<Throwable> suppressedExceptions = Collections.emptyList();
+    private List<Throwable> suppressedExceptions = null;
+    /*
+     * This field is lazily initialized when the first suppressed
+     * exception is added.
+     *
+     * OutOfMemoryError is preallocated in the VM for better OOM
+     * diagnosability during VM initialization. Constructor can't
+     * be not invoked. If a new field to be added in the future must
+     * be initialized to non-null, it requires a synchronized VM change.
+     */
 
     /** Message for trying to suppress a null exception. */
     private static final String NULL_CAUSE_MESSAGE = "Cannot suppress a null exception.";
@@ -329,7 +338,7 @@
      *          cause is nonexistent or unknown.
      * @since 1.4
      */
-    public Throwable getCause() {
+    public synchronized Throwable getCause() {
         return (cause==this ? null : cause);
     }
 
@@ -563,7 +572,7 @@
                 s.println("\tat " + traceElement);
 
             // Print suppressed exceptions, if any
-            for (Throwable se : suppressedExceptions)
+            for (Throwable se : getSuppressedExceptions())
                 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION, "\t", dejaVu);
 
             // Print cause, if any
@@ -604,7 +613,7 @@
                 s.println(prefix + "\t... " + framesInCommon + " more");
 
             // Print suppressed exceptions, if any
-            for (Throwable se : suppressedExceptions)
+            for (Throwable se : getSuppressedExceptions())
                 se.printEnclosedStackTrace(s, trace, SUPPRESSED_CAPTION,
                                            prefix +"\t", dejaVu);
 
@@ -747,7 +756,9 @@
             if (defensiveCopy[i] == null)
                 throw new NullPointerException("stackTrace[" + i + "]");
 
-        this.stackTrace = defensiveCopy;
+        synchronized (this) {
+            this.stackTrace = defensiveCopy;
+        }
     }
 
     /**
@@ -772,11 +783,11 @@
     private void readObject(ObjectInputStream s)
         throws IOException, ClassNotFoundException {
         s.defaultReadObject();     // read in all fields
-        List<Throwable> suppressed = Collections.emptyList();
+        List<Throwable> suppressed = null;
         if (suppressedExceptions != null &&
             !suppressedExceptions.isEmpty()) { // Copy Throwables to new list
             suppressed = new ArrayList<Throwable>();
-            for(Throwable t : suppressedExceptions) {
+            for (Throwable t : suppressedExceptions) {
                 if (t == null)
                     throw new NullPointerException(NULL_CAUSE_MESSAGE);
                 suppressed.add(t);
@@ -819,7 +830,7 @@
         if (exception == this)
             throw new IllegalArgumentException("Self-suppression not permitted");
 
-        if (suppressedExceptions.size() == 0)
+        if (suppressedExceptions == null)
             suppressedExceptions = new ArrayList<Throwable>();
         suppressedExceptions.add(exception);
     }
@@ -835,7 +846,10 @@
      *         suppressed to deliver this exception.
      * @since 1.7
      */
-    public Throwable[] getSuppressedExceptions() {
-        return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
+    public synchronized Throwable[] getSuppressedExceptions() {
+        if (suppressedExceptions == null)
+            return EMPTY_THROWABLE_ARRAY;
+        else
+            return suppressedExceptions.toArray(EMPTY_THROWABLE_ARRAY);
     }
 }