1 /*
   2  * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 import java.io.*;
  25 import java.util.*;
  26 
  27 /*
  28  * @test
  29  * @bug     6911258 6962571 6963622 6991528 7005628 8012044
  30  * @summary Basic tests of suppressed exceptions
  31  * @author  Joseph D. Darcy
  32  */
  33 
  34 public class SuppressedExceptions {
  35     private static String message = "Bad suppressed exception information";
  36 
  37     public static void main(String... args) throws Exception {
  38         noSelfSuppression();
  39         basicSupressionTest();
  40         serializationTest();
  41         selfReference();
  42         noModification();
  43     }
  44 
  45     private static void noSelfSuppression() {
  46         Throwable throwable = new Throwable();
  47         try {
  48             throwable.addSuppressed(throwable);
  49             throw new RuntimeException("IllegalArgumentException for self-suppresion not thrown.");
  50         } catch (IllegalArgumentException iae) {
  51             // Expected to be here
  52             if (iae.getCause() != throwable)
  53                 throw new RuntimeException("Bad cause after self-suppresion.");
  54         }
  55     }
  56 
  57     private static void basicSupressionTest() {
  58         Throwable throwable = new Throwable();
  59         RuntimeException suppressed = new RuntimeException("A suppressed exception.");
  60         AssertionError repressed  = new AssertionError("A repressed error.");
  61 
  62         Throwable[] t0 = throwable.getSuppressed();
  63         if (t0.length != 0) {
  64             throw new RuntimeException(message);
  65         }
  66         throwable.printStackTrace();
  67 
  68         throwable.addSuppressed(suppressed);
  69         Throwable[] t1 = throwable.getSuppressed();
  70         if (t1.length != 1 ||
  71             t1[0] != suppressed) {throw new RuntimeException(message);
  72         }
  73         throwable.printStackTrace();
  74 
  75         throwable.addSuppressed(repressed);
  76         Throwable[] t2 = throwable.getSuppressed();
  77         if (t2.length != 2 ||
  78             t2[0] != suppressed ||
  79             t2[1] != repressed) {
  80             throw new RuntimeException(message);
  81         }
  82         throwable.printStackTrace();
  83     }
  84 
  85     private static void serializationTest() throws Exception {
  86         /*
  87          * Bytes of the serial form of
  88          *
  89          * (new Throwable())setStackTrace(new StackTraceElement[0])
  90          *
  91          * from JDK 6; suppressedException field will be missing and
  92          * thus default to null upon deserialization.
  93          */
  94         byte[] bytes = {
  95             (byte)0xac, (byte)0xed, (byte)0x00, (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13,
  96             (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e,
  97             (byte)0x67, (byte)0x2e, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61,
  98             (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0xd5, (byte)0xc6, (byte)0x35, (byte)0x27, (byte)0x39,
  99             (byte)0x77, (byte)0xb8, (byte)0xcb, (byte)0x03, (byte)0x00, (byte)0x03, (byte)0x4c, (byte)0x00,
 100             (byte)0x05, (byte)0x63, (byte)0x61, (byte)0x75, (byte)0x73, (byte)0x65, (byte)0x74, (byte)0x00,
 101             (byte)0x15, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c,
 102             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f,
 103             (byte)0x77, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65, (byte)0x3b, (byte)0x4c, (byte)0x00,
 104             (byte)0x0d, (byte)0x64, (byte)0x65, (byte)0x74, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x4d,
 105             (byte)0x65, (byte)0x73, (byte)0x73, (byte)0x61, (byte)0x67, (byte)0x65, (byte)0x74, (byte)0x00,
 106             (byte)0x12, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c,
 107             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69,
 108             (byte)0x6e, (byte)0x67, (byte)0x3b, (byte)0x5b, (byte)0x00, (byte)0x0a, (byte)0x73, (byte)0x74,
 109             (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65,
 110             (byte)0x74, (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76,
 111             (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53,
 112             (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63,
 113             (byte)0x65, (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74,
 114             (byte)0x3b, (byte)0x78, (byte)0x70, (byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x04,
 115             (byte)0x70, (byte)0x75, (byte)0x72, (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a,
 116             (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67,
 117             (byte)0x2e, (byte)0x53, (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72,
 118             (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65,
 119             (byte)0x6e, (byte)0x74, (byte)0x3b, (byte)0x02, (byte)0x46, (byte)0x2a, (byte)0x3c, (byte)0x3c,
 120             (byte)0xfd, (byte)0x22, (byte)0x39, (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
 121             (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0xac, (byte)0xed, (byte)0x00,
 122             (byte)0x05, (byte)0x73, (byte)0x72, (byte)0x00, (byte)0x13, (byte)0x6a, (byte)0x61, (byte)0x76,
 123             (byte)0x61, (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x54,
 124             (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, (byte)0x62, (byte)0x6c, (byte)0x65,
 125             (byte)0xd5, (byte)0xc6, (byte)0x35, (byte)0x27, (byte)0x39, (byte)0x77, (byte)0xb8, (byte)0xcb,
 126             (byte)0x03, (byte)0x00, (byte)0x03, (byte)0x4c, (byte)0x00, (byte)0x05, (byte)0x63, (byte)0x61,
 127             (byte)0x75, (byte)0x73, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x15, (byte)0x4c, (byte)0x6a,
 128             (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67,
 129             (byte)0x2f, (byte)0x54, (byte)0x68, (byte)0x72, (byte)0x6f, (byte)0x77, (byte)0x61, (byte)0x62,
 130             (byte)0x6c, (byte)0x65, (byte)0x3b, (byte)0x4c, (byte)0x00, (byte)0x0d, (byte)0x64, (byte)0x65,
 131             (byte)0x74, (byte)0x61, (byte)0x69, (byte)0x6c, (byte)0x4d, (byte)0x65, (byte)0x73, (byte)0x73,
 132             (byte)0x61, (byte)0x67, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x12, (byte)0x4c, (byte)0x6a,
 133             (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c, (byte)0x6e, (byte)0x67, (byte)0x3b,
 134             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x72, (byte)0x69,
 135             (byte)0x5b, (byte)0x00, (byte)0x0a, (byte)0x73, (byte)0x74, (byte)0x61, (byte)0x63, (byte)0x6b,
 136             (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x74, (byte)0x00, (byte)0x1e,
 137             (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61, (byte)0x2f, (byte)0x6c,
 138             (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2f, (byte)0x53, (byte)0x74, (byte)0x61, (byte)0x63,
 139             (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65, (byte)0x45, (byte)0x6c,
 140             (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x3b, (byte)0x78, (byte)0x70,
 141             (byte)0x71, (byte)0x00, (byte)0x7e, (byte)0x00, (byte)0x04, (byte)0x70, (byte)0x75, (byte)0x72,
 142             (byte)0x00, (byte)0x1e, (byte)0x5b, (byte)0x4c, (byte)0x6a, (byte)0x61, (byte)0x76, (byte)0x61,
 143             (byte)0x2e, (byte)0x6c, (byte)0x61, (byte)0x6e, (byte)0x67, (byte)0x2e, (byte)0x53, (byte)0x74,
 144             (byte)0x61, (byte)0x63, (byte)0x6b, (byte)0x54, (byte)0x72, (byte)0x61, (byte)0x63, (byte)0x65,
 145             (byte)0x45, (byte)0x6c, (byte)0x65, (byte)0x6d, (byte)0x65, (byte)0x6e, (byte)0x74, (byte)0x3b,
 146             (byte)0x02, (byte)0x46, (byte)0x2a, (byte)0x3c, (byte)0x3c, (byte)0xfd, (byte)0x22, (byte)0x39,
 147             (byte)0x02, (byte)0x00, (byte)0x00, (byte)0x78, (byte)0x70,
 148         };
 149 
 150         try(ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
 151             ObjectInputStream ois = new ObjectInputStream(bais)) {
 152             Object o = ois.readObject();
 153             Throwable throwable = (Throwable) o;
 154 
 155             System.err.println("TESTING SERIALIZED EXCEPTION");
 156 
 157             Throwable[] t0 = throwable.getSuppressed();
 158             if (t0.length != 0) { // Will fail if t0 is null.
 159                 throw new RuntimeException(message);
 160             }
 161             throwable.printStackTrace();
 162         }
 163     }
 164 
 165     private static void selfReference() {
 166         Throwable throwable1 = new RuntimeException();
 167         Throwable throwable2 = new AssertionError();
 168         throwable1.initCause(throwable2);
 169         throwable2.initCause(throwable1);
 170 
 171         throwable1.printStackTrace();
 172 
 173         throwable1.addSuppressed(throwable2);
 174         throwable2.addSuppressed(throwable1);
 175 
 176         throwable1.printStackTrace();
 177     }
 178 
 179     private static void noModification() {
 180         Throwable t = new NoSuppression(false);
 181 
 182         Throwable[] t0 = t.getSuppressed();
 183         if (t0.length != 0)
 184             throw new RuntimeException("Bad nonzero length of suppressed exceptions.");
 185 
 186         t.addSuppressed(new ArithmeticException());
 187 
 188         // Make sure a suppressed exception did *not* get added.
 189         t0 = t.getSuppressed();
 190         if (t0.length != 0)
 191             throw new RuntimeException("Bad nonzero length of suppressed exceptions.");
 192 
 193         Throwable suppressed = new ArithmeticException();
 194         t = new NoSuppression(true); // Suppression enabled
 195         // Make sure addSuppressed(null) throws an NPE
 196         try {
 197             t.addSuppressed(null);
 198             throw new RuntimeException("NPE not thrown!");
 199         } catch(NullPointerException e) {
 200             ; // Expected
 201         }
 202         t.addSuppressed(suppressed);
 203         t0 = t.getSuppressed();
 204         if (t0.length != 1 || t0[0] != suppressed)
 205             throw new RuntimeException("Expected suppression did not occur.");
 206     }
 207 
 208     private static class NoSuppression extends Throwable {
 209         public NoSuppression(boolean enableSuppression) {
 210             super("The medium.", null, enableSuppression, true);
 211         }
 212     }
 213 }