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