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