1 /* 2 * Copyright (c) 2019, 2020, 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 * @library /test/lib 27 * @modules java.base/jdk.internal.misc 28 * jdk.compiler 29 * @compile HiddenClassSigTest.java 30 * @run main/othervm/native -agentlib:HiddenClassSigTest P.Q.HiddenClassSigTest 31 */ 32 33 package P.Q; 34 35 import java.io.ByteArrayOutputStream; 36 import java.io.File; 37 import java.io.FileInputStream; 38 39 import java.lang.invoke.MethodHandles; 40 import java.lang.invoke.MethodHandles.Lookup; 41 import java.nio.file.Files; 42 import java.nio.file.Path; 43 import java.nio.file.Paths; 44 45 import jdk.test.lib.Utils; 46 47 48 interface HCInterf<T> { hcMethod(T t)49 String hcMethod(T t); 50 } 51 52 class HiddenClassSig<T> implements HCInterf<T> { realTest()53 private String realTest() { return "HiddenClassSig: "; } 54 hcMethod(T t)55 public String hcMethod(T t) { 56 String str = realTest(); 57 return str + t.toString(); 58 } 59 } 60 61 public class HiddenClassSigTest { log(String str)62 private static void log(String str) { System.out.println(str); } 63 64 private static final String HCName = "P/Q/HiddenClassSig.class"; 65 private static final Path CLASSES_DIR = Paths.get(Utils.TEST_CLASSES); 66 private static final String LOG_PREFIX = "HiddenClassSigTest: "; 67 checkHiddenClass(Class klass, String sig)68 static native void checkHiddenClass(Class klass, String sig); checkHiddenClassArray(Class array, String sig)69 static native void checkHiddenClassArray(Class array, String sig); checkFailed()70 static native boolean checkFailed(); // get native agent failing status 71 72 static { 73 try { 74 System.loadLibrary("HiddenClassSigTest"); 75 } catch (UnsatisfiedLinkError ule) { 76 System.err.println("Could not load HiddenClassSigTest library"); 77 System.err.println("java.library.path: " 78 + System.getProperty("java.library.path")); 79 throw ule; 80 } 81 } 82 defineHiddenClass(String classFileName)83 static Class<?> defineHiddenClass(String classFileName) throws Exception { 84 Lookup lookup = MethodHandles.lookup(); 85 byte[] bytes = Files.readAllBytes(CLASSES_DIR.resolve(classFileName)); 86 Class<?> hc = lookup.defineHiddenClass(bytes, false).lookupClass(); 87 return hc; 88 } 89 90 // print all name variations logClassInfo(Class<?> klass)91 static void logClassInfo(Class<?> klass) { 92 log("\n### Testing class: " + klass); 93 log(LOG_PREFIX + "isHidden: " + klass.isHidden()); 94 log(LOG_PREFIX + "getName: " + klass.getName()); 95 log(LOG_PREFIX + "typeName: " + klass.getTypeName()); 96 log(LOG_PREFIX + "toString: " + klass.toString()); 97 log(LOG_PREFIX + "toGenStr: " + klass.toGenericString()); 98 log(LOG_PREFIX + "elem type: " + klass.componentType()); 99 } 100 101 private static final String HC_NAME = "P.Q.HiddenClassSig"; 102 private static final String HC_SUFFIX_REGEX = "0x[0-9a-f]+"; 103 checkName(Class<?> klass, String name, String toString)104 static boolean checkName(Class<?> klass, String name, String toString) { 105 boolean failed = false; 106 String regex = ""; 107 Class<?> c = klass; 108 109 // for an array add the prefix "[" for each dimension 110 while (c.isArray()) { 111 regex = "\\[" + regex; 112 c = c.componentType(); 113 } 114 // construct the expected name 115 if (klass.isArray()) { 116 regex += "L" + HC_NAME + "/" + HC_SUFFIX_REGEX + ";"; 117 } else { 118 regex = HC_NAME + "/" + HC_SUFFIX_REGEX; 119 } 120 // check the name matches the expected 121 if (!name.matches(regex)) { 122 log("Test FAIL: result of Class::getName" + " \"" + name + "\" does not match " + regex); 123 failed = true; 124 } 125 // check the string name matches the expected 126 if (!toString.matches("class " + regex)) { 127 log("Test FAIL: result of Class::toString" + " \"" + name + "\" does not match " + regex); 128 failed = true; 129 } 130 return failed; 131 } 132 checkTypeName(Class<?> klass, String name)133 static boolean checkTypeName(Class<?> klass, String name) { 134 boolean failed = false; 135 // construct the expected type name 136 String regex = HC_NAME + "/" + HC_SUFFIX_REGEX; 137 Class<?> c = klass; 138 139 // for an array add the suffix "[]" for each dimension 140 while (c.isArray()) { 141 c = c.componentType(); 142 regex = regex + "\\[\\]"; 143 } 144 // check the type name matches the expected 145 if (!name.matches(regex)) { 146 log("Test FAIL: result of Class::getTypeName" + " \"" + name + "\" does not match " + regex); 147 failed = true; 148 } 149 return failed; 150 } 151 checkGenericString(Class<?> klass, String name)152 static boolean checkGenericString(Class<?> klass, String name) { 153 boolean failed = false; 154 Class<?> c = klass; 155 // construct the expected generic string 156 String regex = HC_NAME + "/" + HC_SUFFIX_REGEX + "<T>"; 157 158 // add the expected name prefix for a non-array class 159 if (!klass.isArray()) { 160 regex = "class " + regex; 161 } 162 // for an array get the bottom component class 163 while (c.isArray()) { 164 c = c.componentType(); 165 regex = regex + "\\[\\]"; 166 } 167 // check the generic string matches the expected 168 if (!name.matches(regex)) { 169 log("Test FAIL: result of Class::toGenericString" + " \"" + name + "\" does not match " + regex); 170 failed = true; 171 } 172 return failed; 173 } 174 checkDescriptorString(Class<?> klass, String name)175 static boolean checkDescriptorString(Class<?> klass, String name) { 176 boolean failed = false; 177 // construct the expected descriptor string 178 String regex = "L" + HC_NAME.replace('.', '/') + "." + HC_SUFFIX_REGEX + ";"; 179 Class<?> c = klass; 180 181 // for array get the bottom component class 182 while (c.isArray()) { 183 regex = "\\[" + regex; 184 c = c.componentType(); 185 } 186 // check the descriptor string matches the expected 187 if (!name.matches(regex)) { 188 log("Test FAIL: result of Class::descriptorString" + " \"" + name + "\" does not match " + regex); 189 failed = true; 190 } 191 return failed; 192 } 193 testClass(Class<?> klass)194 static boolean testClass(Class<?> klass) { 195 boolean failed = false; 196 logClassInfo(klass); 197 198 // verify all name variations 199 failed |= checkName(klass, klass.getName(), klass.toString()); 200 failed |= checkTypeName(klass, klass.getTypeName()); 201 failed |= checkGenericString(klass, klass.toGenericString()); 202 failed |= checkDescriptorString(klass, klass.descriptorString()); 203 204 // an array class is never hidden 205 if (klass.isArray() && klass.isHidden()) { 206 log("Test FAIL: an array class is never hidden"); 207 failed = true; 208 } 209 210 // verify hidden class array or class by the native agent 211 if (klass.isArray()) { 212 checkHiddenClassArray(klass, klass.descriptorString()); 213 } else { 214 checkHiddenClass(klass, klass.descriptorString()); 215 } 216 return failed; 217 } 218 main(String args[])219 public static void main(String args[]) throws Exception { 220 log(LOG_PREFIX + "started"); 221 222 // define a hidden class to test 223 Class<?> hc = defineHiddenClass(HCName); 224 225 // allocate a hidden class instance to test 226 HCInterf<String> testObj = (HCInterf<String>)hc.newInstance(); 227 228 String str = testObj.hcMethod("Test generic hidden class"); 229 log(LOG_PREFIX + "hc.hcMethod() returned string: " + str); 230 231 // test all hidden class name/signature variations 232 boolean failed = testClass(hc); 233 234 // test all hidden class array name/signature variations 235 Class<?> hcArr = hc.arrayType(); 236 failed |= testClass(hcArr); 237 238 // test all hidden class double array name/signature variations 239 Class<?> hcArrArr = hcArr.arrayType(); 240 failed |= testClass(hcArrArr); 241 242 if (failed) { // check the java part failing status 243 throw new RuntimeException("FAIL: failed status from java part"); 244 } 245 if (checkFailed()) { // check the native agent failing status 246 throw new RuntimeException("FAIL: failed status from native agent"); 247 } 248 log(LOG_PREFIX + "finished"); 249 } 250 } 251