1 /*
   2  * Copyright (c) 2018, 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
  26  * @bug 8046171
  27  * @summary Test access to private methods between nestmates where there
  28  *          is an inheritance hierarchy and we invoke private methods that
  29  *          exist in specific classes in the hierarchy.
  30  * @compile ../NestmatesJNI.java
  31  * @run main/othervm/native  TestJNIHierarchy
  32  * @run main/othervm/native -Xcheck:jni TestJNIHierarchy
  33  */
  34 
  35 public class TestJNIHierarchy {
  36 
  37     // Unlike reflection, the calling context is not relevant to JNI
  38     // calls, but we keep the same structure as the reflection tests.
  39 
  40     static final String METHOD = "priv_invoke";
  41 
  42     static class NestedA extends ExternalSuper {
  43         static final String ID =  "NestedA::priv_invoke";
  44         private String priv_invoke() {
  45             return ID;
  46         }
  47         static void checkA(NestedA a) {
  48             String res = NestmatesJNI.callStringVoid(a,
  49                                                      NestedA.class.getName(),
  50                                                      METHOD,
  51                                                      true);
  52             verifyEquals(res, NestedA.ID);
  53             res = NestmatesJNI.callStringVoid(a,
  54                                               NestedA.class.getName(),
  55                                               METHOD,
  56                                               false);
  57             verifyEquals(res, NestedA.ID);
  58         }
  59     }
  60 
  61     static class NestedB extends NestedA {
  62         static final String ID =  "NestedB::priv_invoke";
  63         private String priv_invoke() {
  64             return ID;
  65         }
  66         static void checkA(NestedA a) {
  67             String res = NestmatesJNI.callStringVoid(a,
  68                                                      NestedA.class.getName(),
  69                                                      METHOD,
  70                                                      true);
  71             verifyEquals(res, NestedA.ID);
  72 
  73             res = NestmatesJNI.callStringVoid(a,
  74                                               NestedA.class.getName(),
  75                                               METHOD,
  76                                               false);
  77             verifyEquals(res, NestedA.ID);
  78         }
  79     }
  80 
  81     static class NestedC extends NestedB {
  82         static final String ID =  "NestedC::priv_invoke";
  83         private String priv_invoke() {
  84             return ID;
  85         }
  86         static void checkA(NestedA a) {
  87             String res = NestmatesJNI.callStringVoid(a,
  88                                                      NestedA.class.getName(),
  89                                                      METHOD,
  90                                                      true);
  91             verifyEquals(res, NestedA.ID);
  92         }
  93     }
  94 
  95     static void checkA(NestedA a) {
  96         String res = NestmatesJNI.callStringVoid(a,
  97                                                  NestedA.class.getName(),
  98                                                  METHOD,
  99                                                  true);
 100         verifyEquals(res, NestedA.ID);
 101 
 102         res = NestmatesJNI.callStringVoid(a,
 103                                           NestedA.class.getName(),
 104                                           METHOD,
 105                                           false);
 106         verifyEquals(res, NestedA.ID);
 107     }
 108 
 109     static void checkB(NestedB b) {
 110         String res = NestmatesJNI.callStringVoid(b,
 111                                                  NestedB.class.getName(),
 112                                                  METHOD,
 113                                                  true);
 114         verifyEquals(res, NestedB.ID);
 115 
 116         res = NestmatesJNI.callStringVoid(b,
 117                                           NestedB.class.getName(),
 118                                           METHOD,
 119                                           false);
 120         verifyEquals(res, NestedB.ID);
 121 
 122     }
 123 
 124     static void checkC(NestedC c) {
 125         String res = NestmatesJNI.callStringVoid(c,
 126                                                  NestedC.class.getName(),
 127                                                  METHOD,
 128                                                  true);
 129         verifyEquals(res, NestedC.ID);
 130 
 131         res = NestmatesJNI.callStringVoid(c,
 132                                           NestedC.class.getName(),
 133                                           METHOD,
 134                                           false);
 135         verifyEquals(res, NestedC.ID);
 136     }
 137 
 138 
 139     // Access to private members of classes outside the nest is
 140     // not permitted in general, but JNI ignores all access checks.
 141 
 142     static void checkExternalSuper(ExternalSuper s) {
 143         String res = NestmatesJNI.callStringVoid(s,
 144                                                  ExternalSuper.class.getName(),
 145                                                  METHOD,
 146                                                  true);
 147         verifyEquals(res, ExternalSuper.ID);
 148 
 149         res = NestmatesJNI.callStringVoid(s,
 150                                           ExternalSuper.class.getName(),
 151                                           METHOD,
 152                                           false);
 153         verifyEquals(res, ExternalSuper.ID);
 154     }
 155 
 156     static void checkExternalSub(ExternalSub s) {
 157         String res = NestmatesJNI.callStringVoid(s,
 158                                                  ExternalSub.class.getName(),
 159                                                  METHOD,
 160                                                  true);
 161         verifyEquals(res, ExternalSub.ID);
 162 
 163         res = NestmatesJNI.callStringVoid(s,
 164                                           ExternalSub.class.getName(),
 165                                           METHOD,
 166                                           false);
 167         verifyEquals(res, ExternalSub.ID);
 168     }
 169 
 170     static void verifyEquals(String actual, String expected) {
 171         if (!actual.equals(expected)) {
 172             throw new Error("Expected " + expected + " but got " + actual);
 173         }
 174         System.out.println("Check passed for " + expected);
 175     }
 176 
 177     public static void main(String[] args) {
 178         NestedA a = new NestedA();
 179         NestedB b = new NestedB();
 180         NestedC c = new NestedC();
 181         ExternalSub sub = new ExternalSub();
 182         ExternalSuper sup = new ExternalSuper();
 183 
 184         checkExternalSuper(sup);
 185         checkExternalSuper(a);
 186         checkExternalSuper(b);
 187         checkExternalSuper(c);
 188         checkExternalSuper(sub);
 189 
 190         checkA(a);
 191         checkA(b);
 192         checkA(c);
 193         checkA(sub);
 194 
 195         NestedA.checkA(a);
 196         NestedA.checkA(b);
 197         NestedA.checkA(c);
 198         NestedA.checkA(sub);
 199 
 200         NestedB.checkA(a);
 201         NestedB.checkA(b);
 202         NestedB.checkA(c);
 203         NestedB.checkA(sub);
 204 
 205         NestedC.checkA(a);
 206         NestedC.checkA(b);
 207         NestedC.checkA(c);
 208         NestedC.checkA(sub);
 209 
 210         checkB(b);
 211         checkB(c);
 212         checkB(sub);
 213 
 214         checkC(c);
 215         checkC(sub);
 216 
 217         checkExternalSub(sub);
 218     }
 219 }
 220 
 221 // Classes that are not part of the nest.
 222 // Being non-public allows us to declare them in this file.
 223 
 224 class ExternalSuper {
 225     static final String ID =  "ExternalSuper::priv_invoke";
 226     private String priv_invoke() {
 227         return ID;
 228     }
 229 }
 230 
 231 
 232 class ExternalSub extends TestJNIHierarchy.NestedC {
 233     static final String ID =  "ExternalSub::priv_invoke";
 234     private String priv_invoke() {
 235         return ID;
 236     }
 237 }