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 #include <string.h> 25 #include "jvmti.h" 26 27 extern "C" { 28 29 static const char* EXP_INTERF_SIG = "LP/Q/HCInterf;"; 30 static const char* SIG_START = "LP/Q/HiddenClassSig"; 31 static const size_t SIG_START_LEN = strlen(SIG_START); 32 static const int ACC_INTERFACE = 0x0200; // Interface class modifiers bit 33 34 static jvmtiEnv *jvmti = NULL; 35 static jint class_load_count = 0; 36 static jint class_prep_count = 0; 37 static bool failed = false; 38 39 #define LOG0(str) { printf(str); fflush(stdout); } 40 #define LOG1(str, arg) { printf(str, arg); fflush(stdout); } 41 #define LOG2(str, arg1, arg2) { printf(str, arg1, arg2); fflush(stdout); } 42 43 #define CHECK_JVMTI_ERROR(jni, err, msg) \ 44 if (err != JVMTI_ERROR_NONE) { \ 45 LOG1("CHECK_JVMTI_ERROR: JVMTI function returned error: %d\n", err); \ 46 jni->FatalError(msg); \ 47 return; \ 48 } 49 50 /* Return the jmethodID of j.l.Class.isHidden() method. */ 51 static jmethodID 52 is_hidden_mid(JNIEnv* jni) { 53 char* csig = NULL; 54 jint count = 0; 55 jmethodID *methods = NULL; 56 jclass clazz = jni->FindClass("java/lang/Class"); 57 if (clazz == NULL) { 58 jni->FatalError("is_hidden_mid: Error: FindClass returned NULL for java/lang/Class\n"); 59 return NULL; 60 } 61 62 // find the jmethodID of j.l.Class.isHidden() method 63 jmethodID mid = jni->GetMethodID(clazz, "isHidden", "()Z"); 64 if (mid == NULL) { 65 jni->FatalError("is_hidden_mid: Error in jni GetMethodID: Cannot find j.l.Class.isHidden method\n"); 66 } 67 return mid; 68 } 69 70 /* Return true if the klass is hidden. */ 71 static bool 72 is_hidden(JNIEnv* jni, jclass klass) { 73 static jmethodID is_hid_mid = NULL; 74 75 if (is_hid_mid == NULL) { 76 is_hid_mid = is_hidden_mid(jni); 77 } 78 // invoke j.l.Class.isHidden() method 79 bool res = jni->CallBooleanMethod(klass, is_hid_mid); 80 if (jni->ExceptionCheck()) { 81 jni->ExceptionDescribe(); 82 jni->FatalError("is_hidden: Exception in jni CallBooleanMethod\n"); 83 } 84 return res; 85 } 86 87 /* Check the class signature matches the expected. */ 88 static void 89 check_class_signature(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, bool is_hidden, const char* exp_sig) { 90 jint class_modifiers = 0; 91 char* sig = NULL; 92 char* gsig = NULL; 93 jvmtiError err; 94 95 // get class signature 96 err = jvmti->GetClassSignature(klass, &sig, &gsig); 97 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class: Error in JVMTI GetClassSignature"); 98 99 LOG1("check_class_signature: class with sig: %s\n", sig); 100 LOG1("check_class_signature: class with gsig: %s\n", gsig); 101 102 if (strcmp(sig, exp_sig) != 0) { 103 LOG2("check_class_signature: FAIL: Hidden class signature %s does not match expected: %s\n", sig, exp_sig); 104 failed = true; 105 } 106 if (is_hidden && gsig == NULL) { 107 LOG0("check_class_signature: FAIL: unexpected NULL generic signature for hidden class\n"); 108 failed = true; 109 } 110 } 111 112 /* Test hidden class flags: it should not be interface, array nor modifiable. */ 113 static void 114 check_hidden_class_flags(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) { 115 jint modifiers = 0; 116 jboolean flag = false; 117 jvmtiError err; 118 119 err = jvmti->GetClassModifiers(klass, &modifiers); 120 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI GetClassModifiers"); 121 LOG1("check_hidden_class_flags: hidden class modifiers: 0x%x\n", modifiers); 122 if ((modifiers & ACC_INTERFACE) != 0) { 123 LOG0("check_hidden_class_flags: FAIL: unexpected ACC_INTERFACE bit in hidden class modifiers\n"); 124 failed = true; 125 return; 126 } 127 128 err = jvmti->IsInterface(klass, &flag); 129 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsInterface"); 130 if (flag) { 131 LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be interface\n"); 132 failed = true; 133 return; 134 } 135 136 err = jvmti->IsArrayClass(klass, &flag); 137 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsArrayClass"); 138 if (flag) { 139 LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be array\n"); 140 failed = true; 141 return; 142 } 143 err = jvmti->IsModifiableClass(klass, &flag); 144 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsModifiableClass"); 145 if (flag) { 146 LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be modifiable\n"); 147 failed = true; 148 } 149 } 150 151 /* Test GetClassLoaderClasses: it should not return any hidden classes. */ 152 static void 153 check_hidden_class_loader(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) { 154 jint count = 0; 155 jobject loader = NULL; 156 jclass* loader_classes = NULL; 157 jboolean found = false; 158 jvmtiError err; 159 160 err = jvmti->GetClassLoader(klass, &loader); 161 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoader"); 162 163 jni->EnsureLocalCapacity(256); // to avoid warnings: JNI local refs NN exceeds capacity 164 165 err = jvmti->GetClassLoaderClasses(loader, &count, &loader_classes); 166 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoaderClasses"); 167 168 for (int idx = 0; idx < count; idx++) { 169 char* sig = NULL; 170 jclass kls = loader_classes[idx]; 171 172 // GetClassLoaderClasses should not return any hidden classes 173 if (!is_hidden(jni, kls)) { 174 continue; 175 } 176 // get class signature 177 err = jvmti->GetClassSignature(kls, &sig, NULL); 178 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassSignature"); 179 180 LOG1("check_hidden_class_loader: FAIL: JVMTI GetClassLoaderClasses returned hidden class: %s\n", sig); 181 failed = true; 182 return; 183 } 184 LOG0("check_hidden_class_loader: not found hidden class in its loader classes as expected\n"); 185 } 186 187 /* Test the hidden class implements expected interface. */ 188 static void 189 check_hidden_class_impl_interf(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) { 190 char* sig = NULL; 191 jint count = 0; 192 jclass* interfaces = NULL; 193 jvmtiError err; 194 195 // check that hidden class implements just one interface 196 err = jvmti->GetImplementedInterfaces(klass, &count, &interfaces); 197 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetImplementedInterfaces"); 198 if (count != 1) { 199 LOG1("check_hidden_class_impl_interf: FAIL: implemented interfaces count: %d, expected to be 1\n", count); 200 failed = true; 201 return; 202 } 203 // get interface signature 204 err = jvmti->GetClassSignature(interfaces[0], &sig, NULL); 205 CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetClassSignature for implemented interface"); 206 207 // check the interface signature is matching the expected 208 if (strcmp(sig, EXP_INTERF_SIG) != 0) { 209 LOG2("check_hidden_class_impl_interf: FAIL: implemented interface signature: %s, expected to be: %s\n", 210 sig, EXP_INTERF_SIG); 211 failed = true; 212 } 213 } 214 215 /* Test hidden class. */ 216 static void 217 check_hidden_class(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, const char* exp_sig) { 218 char* source_file_name = NULL; 219 220 LOG1("\n### Native agent: check_hidden_class started: class: %s\n", exp_sig); 221 222 check_class_signature(jvmti, jni, klass, true /* not hidden */, exp_sig); 223 if (failed) return; 224 225 check_hidden_class_flags(jvmti, jni, klass); 226 if (failed) return; 227 228 check_hidden_class_loader(jvmti, jni, klass); 229 if (failed) return; 230 231 check_hidden_class_impl_interf(jvmti, jni, klass); 232 if (failed) return; 233 234 LOG0("### Native agent: check_hidden_class finished\n"); 235 } 236 237 /* Test hidden class array. */ 238 static void 239 check_hidden_class_array(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass_array, const char* exp_sig) { 240 char* source_file_name = NULL; 241 242 LOG1("\n### Native agent: check_hidden_class_array started: array: %s\n", exp_sig); 243 244 check_class_signature(jvmti, jni, klass_array, false /* is hidden */, exp_sig); 245 if (failed) return; 246 247 LOG0("### Native agent: check_hidden_class_array finished\n"); 248 } 249 250 /* Process a CLASS_LOAD or aClassPrepare event. */ 251 static void process_class_event(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, 252 jint* event_count_ptr, const char* event_name) { 253 char* sig = NULL; 254 char* gsig = NULL; 255 jvmtiError err; 256 257 // get class signature 258 err = jvmti->GetClassSignature(klass, &sig, &gsig); 259 CHECK_JVMTI_ERROR(jni, err, "ClassLoad event: Error in JVMTI GetClassSignature"); 260 261 // check if this is an expected class event for hidden class 262 if (strlen(sig) > strlen(SIG_START) && 263 strncmp(sig, SIG_START, SIG_START_LEN) == 0 && 264 is_hidden(jni, klass)) { 265 (*event_count_ptr)++; 266 if (gsig == NULL) { 267 LOG1("%s event: FAIL: GetClassSignature returned NULL generic signature for hidden class\n", event_name); 268 failed = true; 269 } 270 LOG2("%s event: hidden class with sig: %s\n", event_name, sig); 271 LOG2("%s event: hidden class with gsig: %s\n", event_name, gsig); 272 } 273 } 274 275 /* Check CLASS_LOAD event is generated for the given hidden class. */ 276 static void JNICALL 277 ClassLoad(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) { 278 process_class_event(jvmti, jni, klass, &class_load_count, "ClassLoad"); 279 } 280 281 /* Check CLASS_PREPARE event is generated for the given hidden class. */ 282 static void JNICALL 283 ClassPrepare(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) { 284 process_class_event(jvmti, jni, klass, &class_prep_count, "ClassPrepare"); 285 } 286 287 /* Enable CLASS_LOAD event notification mode. */ 288 static void JNICALL 289 VMInit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) { 290 jvmtiError err; 291 292 printf("VMInit event: SIG_START: %s, SIG_START_LEN: %d\n", SIG_START, (int)SIG_START_LEN); 293 fflush(stdout); 294 295 // enable ClassLoad event notification mode 296 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL); 297 CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassLoad events notification"); 298 299 // enable ClassPrepare event notification mode 300 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL); 301 CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassPrepare events notification"); 302 } 303 304 JNIEXPORT jint JNICALL 305 Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 306 jvmtiEventCallbacks callbacks; 307 jvmtiError err; 308 309 LOG0("Agent_OnLoad: started\n"); 310 if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) { 311 LOG0("Agent_OnLoad: Error in GetEnv in obtaining jvmtiEnv*\n"); 312 failed = true; 313 return JNI_ERR; 314 } 315 316 // set required event callbacks 317 memset(&callbacks, 0, sizeof(callbacks)); 318 callbacks.ClassLoad = &ClassLoad; 319 callbacks.ClassPrepare = &ClassPrepare; 320 callbacks.VMInit = &VMInit; 321 322 err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks)); 323 if (err != JVMTI_ERROR_NONE) { 324 LOG1("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err); 325 failed = true; 326 return JNI_ERR; 327 } 328 329 // enable VM_INIT event notification mode 330 err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL); 331 if (err != JVMTI_ERROR_NONE) { 332 LOG1("Agent_OnLoad: Error in JVMTI SetEventNotificationMode: %d\n", err); 333 failed = true; 334 return JNI_ERR; 335 } 336 337 LOG0("Agent_OnLoad: finished\n"); 338 return JNI_OK; 339 } 340 341 /* Native method: checkHiddenClass(). */ 342 JNIEXPORT void JNICALL 343 Java_P_Q_HiddenClassSigTest_checkHiddenClass(JNIEnv *jni, jclass klass, jclass hidden_klass, jstring exp_sig_str) { 344 const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, NULL); 345 346 if (exp_sig == NULL) { 347 jni->FatalError("check_hidden_class: Error: JNI GetStringChars returned NULL for jstring\n"); 348 return; 349 } 350 check_hidden_class(jvmti, jni, hidden_klass, exp_sig); 351 352 jni->ReleaseStringUTFChars(exp_sig_str, exp_sig); 353 } 354 355 /* Native method: checkHiddenClassArray(). */ 356 JNIEXPORT void JNICALL 357 Java_P_Q_HiddenClassSigTest_checkHiddenClassArray(JNIEnv *jni, jclass klass, jclass hidden_klass_array, jstring exp_sig_str) { 358 const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, NULL); 359 360 if (exp_sig == NULL) { 361 jni->FatalError("check_hidden_class_array: Error: JNI GetStringChars returned NULL for jstring\n"); 362 return; 363 } 364 check_hidden_class_array(jvmti, jni, hidden_klass_array, exp_sig); 365 366 jni->ReleaseStringUTFChars(exp_sig_str, exp_sig); 367 } 368 369 /* Native method: checkFailed(). */ 370 JNIEXPORT jboolean JNICALL 371 Java_P_Q_HiddenClassSigTest_checkFailed(JNIEnv *jni, jclass klass) { 372 if (class_load_count == 0) { 373 // expected ClassLoad event was not generated for hidden class 374 LOG0("Native Agent: FAIL: missed ClassLoad event for hidden class\n"); 375 failed = true; 376 } 377 if (class_prep_count == 0) { 378 // expected ClassPrepare event was not generated for hidden class 379 LOG0("Native Agent: FAIL: missed ClassPrepare event for hidden class\n"); 380 failed = true; 381 } 382 return failed; 383 } 384 385 } // extern "C"