1 /*
   2  * Copyright (c) 2012, 2013, 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 /*
  25  * @test Test8004741.java
  26  * @bug 8004741
  27  * @summary Missing compiled exception handle table entry for multidimensional array allocation
  28  * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers -XX:+SafepointALot -XX:GuaranteedSafepointInterval=100 Test8004741
  29  * @run main/othervm -Xmx64m -Xbatch -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:-TieredCompilation -XX:+StressCompiledExceptionHandlers Test8004741
  30  */
  31 
  32 import java.util.*;
  33 
  34 public class Test8004741 extends Thread {
  35 
  36   static int passed = 0;
  37 
  38   /**
  39    * Loop forever allocating 2-d arrays.
  40    * Catches and rethrows all exceptions; in the case of ThreadDeath, increments passed.
  41    * Note that passed is incremented here because this is the exception handler with
  42    * the smallest scope; we only want to declare success in the case where it is highly
  43    * likely that the test condition
  44    * (exception in 2-d array alloc interrupted by ThreadDeath)
  45    * actually occurs.
  46    */
  47   static int[][] test(int a, int b) throws Exception {
  48     int[][] ar;
  49     try {
  50       ar = new int[a][b];
  51     } catch (ThreadDeath e) {
  52       System.out.println("test got ThreadDeath");
  53       passed++;
  54       throw(e);
  55     }
  56     return ar;
  57   }
  58 
  59   /* Cookbook wait-notify to track progress of test thread. */
  60   Object progressLock = new Object();
  61   private static final int NOT_STARTED = 0;
  62   private static final int RUNNING = 1;
  63   private static final int STOPPING = 2;
  64 
  65   int progressState = NOT_STARTED;
  66 
  67   void toState(int state) {
  68     synchronized (progressLock) {
  69       progressState = state;
  70       progressLock.notify();
  71     }
  72   }
  73 
  74   void waitFor(int state) {
  75     synchronized (progressLock) {
  76       while (progressState < state) {
  77         try {
  78           progressLock.wait();
  79         } catch (InterruptedException e) {
  80           e.printStackTrace();
  81           System.out.println("unexpected InterruptedException");
  82           fail();
  83         }
  84       }
  85       if (progressState > state) {
  86         System.out.println("unexpected test state change, expected " +
  87                             state + " but saw " + progressState);
  88         fail();
  89       }
  90     }
  91   }
  92 
  93   /**
  94    * Loops running test until some sort of an exception or error,
  95    * expects to see ThreadDeath.
  96    */
  97   public void run() {
  98     try {
  99       // Print before state change, so that other thread is most likely
 100       // to see this thread executing calls to test() in a loop.
 101       System.out.println("thread running");
 102       toState(RUNNING);
 103       while (true) {
 104         // (2,2) (2,10) (2,100) were observed to tickle the bug;
 105         test(2, 100);
 106       }
 107     } catch (ThreadDeath e) {
 108       // nothing to say, passing was incremented by the test.
 109     } catch (Throwable e) {
 110       e.printStackTrace();
 111       System.out.println("unexpected Throwable " + e);
 112       fail();
 113     }
 114     toState(STOPPING);
 115   }
 116 
 117   /**
 118    * Runs a single trial of the test in a thread.
 119    * No single trial is definitive, since the ThreadDeath
 120    * exception might not land in the tested region of code.
 121    */
 122   public static void threadTest() throws InterruptedException {
 123     Test8004741 t = new Test8004741();
 124     t.start();
 125     t.waitFor(RUNNING);
 126     Thread.sleep(100);
 127     System.out.println("stopping thread");
 128     t.stop();
 129     t.waitFor(STOPPING);
 130     t.join();
 131   }
 132 
 133   public static void main(String[] args) throws Exception {
 134     // Warm up "test"
 135     // t will never be started.
 136     for (int n = 0; n < 11000; n++) {
 137       test(2, 100);
 138     }
 139 
 140     // Will this sleep help ensure that the compiler is run?
 141     Thread.sleep(500);
 142     passed = 0;
 143 
 144     try {
 145       test(-1, 100);
 146       System.out.println("Missing NegativeArraySizeException #1");
 147       fail();
 148     } catch ( java.lang.NegativeArraySizeException e ) {
 149       System.out.println("Saw expected NegativeArraySizeException #1");
 150     }
 151 
 152     try {
 153       test(100, -1);
 154       fail();
 155       System.out.println("Missing NegativeArraySizeException #2");
 156       fail();
 157     } catch ( java.lang.NegativeArraySizeException e ) {
 158       System.out.println("Saw expected NegativeArraySizeException #2");
 159     }
 160 
 161     /* Test repetitions.  If the test succeeds-mostly, it succeeds,
 162      * as long as it does not crash (the outcome if the exception range
 163      * table entry for the array allocation is missing).
 164      */
 165     int N = 12;
 166     for (int n = 0; n < N; n++) {
 167       threadTest();
 168     }
 169 
 170     if (passed > N/2) {
 171       System.out.println("Saw " + passed + " out of " + N + " possible ThreadDeath hits");
 172       System.out.println("PASSED");
 173     } else {
 174       System.out.println("Too few ThreadDeath hits; expected at least " + N/2 +
 175                          " but saw only " + passed);
 176       fail();
 177     }
 178   }
 179 
 180   static void fail() {
 181     System.out.println("FAILED");
 182     System.exit(97);
 183   }
 184 };