1 /*
   2  * Copyright (c) 2016, 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 /* @test
  25  * @bug 8164086
  26  * @summary regression tests for 8164086, verify correct warning from checked JNI
  27  * @library /test/lib
  28  * @modules java.management
  29  * @run main/native TestCheckedJniExceptionCheck launch
  30  */
  31 
  32 import java.util.List;
  33 import jdk.test.lib.process.ProcessTools;
  34 import jdk.test.lib.process.OutputAnalyzer;
  35 
  36 public class TestCheckedJniExceptionCheck {
  37 
  38     static {
  39         System.loadLibrary("TestCheckedJniExceptionCheck");
  40     }
  41 
  42     int callableMethodInvokeCount = 0;
  43 
  44     static final String EXPECT_WARNING_START = "EXPECT_WARNING_START";
  45     static final String EXPECT_WARNING_END   = "EXPECT_WARNING_END";
  46 
  47     static final String JNI_CHECK_EXCEPTION = "WARNING in native method: JNI call made without checking exceptions when required to from";
  48 
  49     static void printExpectWarningStart(int count) {
  50         System.out.println(EXPECT_WARNING_START + " " + count);
  51     }
  52 
  53     static void printExpectWarningEnd() {
  54         System.out.println(EXPECT_WARNING_END);
  55     }
  56 
  57     public TestCheckedJniExceptionCheck() {
  58         initMethodIds("callableMethod", "()V",
  59                       "callableNestedMethod", "(IZ)V");
  60     }
  61 
  62     public void test() {
  63         testSingleCallNoCheck();
  64         testSingleCallCheck();
  65         testSingleCallNoCheckMultipleTimes();
  66 
  67         testMultipleCallsNoCheck();
  68         testMultipleCallsCheck();
  69 
  70         testNestedSingleCallsNoCheck();
  71         testNestedSingleCallsCheck();
  72         testNestedMultipleCallsNoCheck();
  73         testNestedMultipleCallsCheck();
  74     }
  75 
  76     public void testSingleCallNoCheck() {
  77         System.out.println("testSingleCallNoCheck start");
  78         callJavaFromNative(1, false);
  79         System.out.println("testSingleCallNoCheck end");
  80     }
  81 
  82     public void testSingleCallCheck() {
  83         System.out.println("testSingleCallCheck start");
  84         callJavaFromNative(1, true);
  85         System.out.println("testSingleCallCheck end");
  86     }
  87 
  88     public void testSingleCallNoCheckMultipleTimes() {
  89         System.out.println("testSingleCallNoCheckMultipleTimes start");
  90         callJavaFromNative(1, false);
  91         callJavaFromNative(1, false);
  92         System.out.println("testSingleCallNoCheckMultipleTimes end");
  93     }
  94 
  95     public void testMultipleCallsNoCheck() {
  96         System.out.println("testMultipleCallsNoCheck start");
  97         printExpectWarningStart(1);
  98         callJavaFromNative(2, false);
  99         printExpectWarningEnd();
 100         System.out.println("testMultipleCallsNoCheck end");
 101     }
 102 
 103     public void testMultipleCallsCheck() {
 104         System.out.println("testMultipleCallsCheck start");
 105         callJavaFromNative(2, true);
 106         System.out.println("testMultipleCallsCheck end");
 107     }
 108 
 109     public void testNestedSingleCallsNoCheck() {
 110         System.out.println("testNestedSingleCallsNoCheck start");
 111         callNestedJavaFromNative(1, false);
 112         System.out.println("testNestedSingleCallsNoCheck end");
 113     }
 114 
 115     public void testNestedSingleCallsCheck() {
 116         System.out.println("testNestedSingleCallsCheck start");
 117         callNestedJavaFromNative(1, true);
 118         System.out.println("testNestedSingleCallsCheck end");
 119     }
 120 
 121     public void testNestedMultipleCallsNoCheck() {
 122         System.out.println("testNestedMultipleCallsNoCheck start");
 123         printExpectWarningStart(3);
 124         callNestedJavaFromNative(2, false);
 125         printExpectWarningEnd();
 126         System.out.println("testNestedMultipleCallsNoCheck end");
 127     }
 128 
 129     public void testNestedMultipleCallsCheck() {
 130         System.out.println("testNestedMultipleCallsCheck start");
 131         callNestedJavaFromNative(2, true);
 132         System.out.println("testNestedMultipleCallsCheck end");
 133     }
 134 
 135     public void callableMethod() {
 136         callableMethodInvokeCount++;
 137     }
 138 
 139     public void callableNestedMethod(int nofCalls, boolean withExceptionChecks) {
 140         callJavaFromNative(nofCalls, withExceptionChecks);
 141     }
 142 
 143     public native void callJavaFromNative(int nofCalls, boolean withExceptionChecks);
 144 
 145     public native void callNestedJavaFromNative(int nofCalls, boolean withExceptionChecks);
 146 
 147     private native void initMethodIds(String callableMethodName,
 148                                       String callableMethodSig,
 149                                       String callableNestedMethodName,
 150                                       String callableNestedMethodSig);
 151 
 152 
 153     // Check warnings appear where they should, with start/end statements in output...
 154     static void checkOuputForCorrectWarnings(OutputAnalyzer oa) throws RuntimeException {
 155         List<String> lines = oa.asLines();
 156         int expectedWarnings = 0;
 157         int warningCount = 0;
 158         int lineNo = 0;
 159         for (String line : lines) {
 160             lineNo++;
 161             if (line.startsWith(JNI_CHECK_EXCEPTION)) {
 162                 if (expectedWarnings == 0) {
 163                     oa.reportDiagnosticSummary();
 164                     throw new RuntimeException("Unexpected warning at line " + lineNo);
 165                 }
 166                 warningCount++;
 167                 if (warningCount > expectedWarnings) {
 168                     oa.reportDiagnosticSummary();
 169                     throw new RuntimeException("Unexpected warning at line " + lineNo);
 170                 }
 171             }
 172             else if (line.startsWith(EXPECT_WARNING_START)) {
 173                 String countStr = line.substring(EXPECT_WARNING_START.length() + 1);
 174                 expectedWarnings = Integer.parseInt(countStr);
 175             }
 176             else if (line.startsWith(EXPECT_WARNING_END)) {
 177                 if (warningCount != expectedWarnings) {
 178                     oa.reportDiagnosticSummary();
 179                     throw new RuntimeException("Missing warning at line " + lineNo);
 180                 }
 181                 warningCount = 0;
 182                 expectedWarnings = 0;
 183             }
 184         }
 185         /*
 186         System.out.println("Output looks good...");
 187         oa.reportDiagnosticSummary();
 188         */
 189     }
 190 
 191     public static void main(String[] args) throws Throwable {
 192         if (args == null || args.length == 0) {
 193             new TestCheckedJniExceptionCheck().test();
 194             return;
 195         }
 196 
 197         // launch and check output
 198         checkOuputForCorrectWarnings(ProcessTools.executeTestJvm("-Xcheck:jni",
 199                                                                   "TestCheckedJniExceptionCheck"));
 200     }
 201 
 202 }