Path: blob/master/test/hotspot/jtreg/serviceability/jvmti/HiddenClass/libHiddenClassSigTest.cpp
41155 views
/*1* Copyright (c) 2019, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223#include <string.h>24#include "jvmti.h"2526extern "C" {2728static const char* EXP_INTERF_SIG = "LP/Q/HCInterf;";29static const char* SIG_START = "LP/Q/HiddenClassSig";30static const size_t SIG_START_LEN = strlen(SIG_START);31static const int ACC_INTERFACE = 0x0200; // Interface class modifiers bit3233static jvmtiEnv *jvmti = NULL;34static jint class_load_count = 0;35static jint class_prep_count = 0;36static bool failed = false;3738#define LOG0(str) { printf(str); fflush(stdout); }39#define LOG1(str, arg) { printf(str, arg); fflush(stdout); }40#define LOG2(str, arg1, arg2) { printf(str, arg1, arg2); fflush(stdout); }4142#define CHECK_JVMTI_ERROR(jni, err, msg) \43if (err != JVMTI_ERROR_NONE) { \44LOG1("CHECK_JVMTI_ERROR: JVMTI function returned error: %d\n", err); \45jni->FatalError(msg); \46return; \47}4849/* Return the jmethodID of j.l.Class.isHidden() method. */50static jmethodID51is_hidden_mid(JNIEnv* jni) {52char* csig = NULL;53jint count = 0;54jmethodID *methods = NULL;55jclass clazz = jni->FindClass("java/lang/Class");56if (clazz == NULL) {57jni->FatalError("is_hidden_mid: Error: FindClass returned NULL for java/lang/Class\n");58return NULL;59}6061// find the jmethodID of j.l.Class.isHidden() method62jmethodID mid = jni->GetMethodID(clazz, "isHidden", "()Z");63if (mid == NULL) {64jni->FatalError("is_hidden_mid: Error in jni GetMethodID: Cannot find j.l.Class.isHidden method\n");65}66return mid;67}6869/* Return true if the klass is hidden. */70static bool71is_hidden(JNIEnv* jni, jclass klass) {72static jmethodID is_hid_mid = NULL;7374if (is_hid_mid == NULL) {75is_hid_mid = is_hidden_mid(jni);76}77// invoke j.l.Class.isHidden() method78bool res = jni->CallBooleanMethod(klass, is_hid_mid);79if (jni->ExceptionCheck()) {80jni->ExceptionDescribe();81jni->FatalError("is_hidden: Exception in jni CallBooleanMethod\n");82}83return res;84}8586/* Check the class signature matches the expected. */87static void88check_class_signature(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, bool is_hidden, const char* exp_sig) {89jint class_modifiers = 0;90char* sig = NULL;91char* gsig = NULL;92jvmtiError err;9394// get class signature95err = jvmti->GetClassSignature(klass, &sig, &gsig);96CHECK_JVMTI_ERROR(jni, err, "check_hidden_class: Error in JVMTI GetClassSignature");9798LOG1("check_class_signature: class with sig: %s\n", sig);99LOG1("check_class_signature: class with gsig: %s\n", gsig);100101if (strcmp(sig, exp_sig) != 0) {102LOG2("check_class_signature: FAIL: Hidden class signature %s does not match expected: %s\n", sig, exp_sig);103failed = true;104}105if (is_hidden && gsig == NULL) {106LOG0("check_class_signature: FAIL: unexpected NULL generic signature for hidden class\n");107failed = true;108}109}110111/* Test hidden class flags: it should not be interface, array nor modifiable. */112static void113check_hidden_class_flags(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {114jint modifiers = 0;115jboolean flag = false;116jvmtiError err;117118err = jvmti->GetClassModifiers(klass, &modifiers);119CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI GetClassModifiers");120LOG1("check_hidden_class_flags: hidden class modifiers: 0x%x\n", modifiers);121if ((modifiers & ACC_INTERFACE) != 0) {122LOG0("check_hidden_class_flags: FAIL: unexpected ACC_INTERFACE bit in hidden class modifiers\n");123failed = true;124return;125}126127err = jvmti->IsInterface(klass, &flag);128CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsInterface");129if (flag) {130LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be interface\n");131failed = true;132return;133}134135err = jvmti->IsArrayClass(klass, &flag);136CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsArrayClass");137if (flag) {138LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be array\n");139failed = true;140return;141}142err = jvmti->IsModifiableClass(klass, &flag);143CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_flags: Error in JVMTI IsModifiableClass");144if (flag) {145LOG0("check_hidden_class_flags: FAIL: hidden class is not expected to be modifiable\n");146failed = true;147}148}149150/* Test GetClassLoaderClasses: it should not return any hidden classes. */151static void152check_hidden_class_loader(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {153jint count = 0;154jobject loader = NULL;155jclass* loader_classes = NULL;156jboolean found = false;157jvmtiError err;158159err = jvmti->GetClassLoader(klass, &loader);160CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoader");161162jni->EnsureLocalCapacity(256); // to avoid warnings: JNI local refs NN exceeds capacity163164err = jvmti->GetClassLoaderClasses(loader, &count, &loader_classes);165CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassLoaderClasses");166167for (int idx = 0; idx < count; idx++) {168char* sig = NULL;169jclass kls = loader_classes[idx];170171// GetClassLoaderClasses should not return any hidden classes172if (!is_hidden(jni, kls)) {173continue;174}175// get class signature176err = jvmti->GetClassSignature(kls, &sig, NULL);177CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_loader: Error in JVMTI GetClassSignature");178179LOG1("check_hidden_class_loader: FAIL: JVMTI GetClassLoaderClasses returned hidden class: %s\n", sig);180failed = true;181return;182}183LOG0("check_hidden_class_loader: not found hidden class in its loader classes as expected\n");184}185186/* Test the hidden class implements expected interface. */187static void188check_hidden_class_impl_interf(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass) {189char* sig = NULL;190jint count = 0;191jclass* interfaces = NULL;192jvmtiError err;193194// check that hidden class implements just one interface195err = jvmti->GetImplementedInterfaces(klass, &count, &interfaces);196CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetImplementedInterfaces");197if (count != 1) {198LOG1("check_hidden_class_impl_interf: FAIL: implemented interfaces count: %d, expected to be 1\n", count);199failed = true;200return;201}202// get interface signature203err = jvmti->GetClassSignature(interfaces[0], &sig, NULL);204CHECK_JVMTI_ERROR(jni, err, "check_hidden_class_impl_interf: Error in JVMTI GetClassSignature for implemented interface");205206// check the interface signature is matching the expected207if (strcmp(sig, EXP_INTERF_SIG) != 0) {208LOG2("check_hidden_class_impl_interf: FAIL: implemented interface signature: %s, expected to be: %s\n",209sig, EXP_INTERF_SIG);210failed = true;211}212}213214/* Test hidden class. */215static void216check_hidden_class(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass, const char* exp_sig) {217char* source_file_name = NULL;218219LOG1("\n### Native agent: check_hidden_class started: class: %s\n", exp_sig);220221check_class_signature(jvmti, jni, klass, true /* not hidden */, exp_sig);222if (failed) return;223224check_hidden_class_flags(jvmti, jni, klass);225if (failed) return;226227check_hidden_class_loader(jvmti, jni, klass);228if (failed) return;229230check_hidden_class_impl_interf(jvmti, jni, klass);231if (failed) return;232233LOG0("### Native agent: check_hidden_class finished\n");234}235236/* Test hidden class array. */237static void238check_hidden_class_array(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass_array, const char* exp_sig) {239char* source_file_name = NULL;240241LOG1("\n### Native agent: check_hidden_class_array started: array: %s\n", exp_sig);242243check_class_signature(jvmti, jni, klass_array, false /* is hidden */, exp_sig);244if (failed) return;245246LOG0("### Native agent: check_hidden_class_array finished\n");247}248249/* Process a CLASS_LOAD or aClassPrepare event. */250static void process_class_event(jvmtiEnv* jvmti, JNIEnv* jni, jclass klass,251jint* event_count_ptr, const char* event_name) {252char* sig = NULL;253char* gsig = NULL;254jvmtiError err;255256// get class signature257err = jvmti->GetClassSignature(klass, &sig, &gsig);258CHECK_JVMTI_ERROR(jni, err, "ClassLoad event: Error in JVMTI GetClassSignature");259260// check if this is an expected class event for hidden class261if (strlen(sig) > strlen(SIG_START) &&262strncmp(sig, SIG_START, SIG_START_LEN) == 0 &&263is_hidden(jni, klass)) {264(*event_count_ptr)++;265if (gsig == NULL) {266LOG1("%s event: FAIL: GetClassSignature returned NULL generic signature for hidden class\n", event_name);267failed = true;268}269LOG2("%s event: hidden class with sig: %s\n", event_name, sig);270LOG2("%s event: hidden class with gsig: %s\n", event_name, gsig);271}272}273274/* Check CLASS_LOAD event is generated for the given hidden class. */275static void JNICALL276ClassLoad(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) {277process_class_event(jvmti, jni, klass, &class_load_count, "ClassLoad");278}279280/* Check CLASS_PREPARE event is generated for the given hidden class. */281static void JNICALL282ClassPrepare(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread, jclass klass) {283process_class_event(jvmti, jni, klass, &class_prep_count, "ClassPrepare");284}285286/* Enable CLASS_LOAD event notification mode. */287static void JNICALL288VMInit(jvmtiEnv* jvmti, JNIEnv* jni, jthread thread) {289jvmtiError err;290291printf("VMInit event: SIG_START: %s, SIG_START_LEN: %d\n", SIG_START, (int)SIG_START_LEN);292fflush(stdout);293294// enable ClassLoad event notification mode295err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_LOAD, NULL);296CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassLoad events notification");297298// enable ClassPrepare event notification mode299err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_PREPARE, NULL);300CHECK_JVMTI_ERROR(jni, err, "VMInit event: Error in enabling ClassPrepare events notification");301}302303JNIEXPORT jint JNICALL304Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {305jvmtiEventCallbacks callbacks;306jvmtiError err;307308LOG0("Agent_OnLoad: started\n");309if (jvm->GetEnv((void **) (&jvmti), JVMTI_VERSION) != JNI_OK) {310LOG0("Agent_OnLoad: Error in GetEnv in obtaining jvmtiEnv*\n");311failed = true;312return JNI_ERR;313}314315// set required event callbacks316memset(&callbacks, 0, sizeof(callbacks));317callbacks.ClassLoad = &ClassLoad;318callbacks.ClassPrepare = &ClassPrepare;319callbacks.VMInit = &VMInit;320321err = jvmti->SetEventCallbacks(&callbacks, sizeof(jvmtiEventCallbacks));322if (err != JVMTI_ERROR_NONE) {323LOG1("Agent_OnLoad: Error in JVMTI SetEventCallbacks: %d\n", err);324failed = true;325return JNI_ERR;326}327328// enable VM_INIT event notification mode329err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_VM_INIT, NULL);330if (err != JVMTI_ERROR_NONE) {331LOG1("Agent_OnLoad: Error in JVMTI SetEventNotificationMode: %d\n", err);332failed = true;333return JNI_ERR;334}335336LOG0("Agent_OnLoad: finished\n");337return JNI_OK;338}339340/* Native method: checkHiddenClass(). */341JNIEXPORT void JNICALL342Java_P_Q_HiddenClassSigTest_checkHiddenClass(JNIEnv *jni, jclass klass, jclass hidden_klass, jstring exp_sig_str) {343const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, NULL);344345if (exp_sig == NULL) {346jni->FatalError("check_hidden_class: Error: JNI GetStringChars returned NULL for jstring\n");347return;348}349check_hidden_class(jvmti, jni, hidden_klass, exp_sig);350351jni->ReleaseStringUTFChars(exp_sig_str, exp_sig);352}353354/* Native method: checkHiddenClassArray(). */355JNIEXPORT void JNICALL356Java_P_Q_HiddenClassSigTest_checkHiddenClassArray(JNIEnv *jni, jclass klass, jclass hidden_klass_array, jstring exp_sig_str) {357const char* exp_sig = jni->GetStringUTFChars(exp_sig_str, NULL);358359if (exp_sig == NULL) {360jni->FatalError("check_hidden_class_array: Error: JNI GetStringChars returned NULL for jstring\n");361return;362}363check_hidden_class_array(jvmti, jni, hidden_klass_array, exp_sig);364365jni->ReleaseStringUTFChars(exp_sig_str, exp_sig);366}367368/* Native method: checkFailed(). */369JNIEXPORT jboolean JNICALL370Java_P_Q_HiddenClassSigTest_checkFailed(JNIEnv *jni, jclass klass) {371if (class_load_count == 0) {372// expected ClassLoad event was not generated for hidden class373LOG0("Native Agent: FAIL: missed ClassLoad event for hidden class\n");374failed = true;375}376if (class_prep_count == 0) {377// expected ClassPrepare event was not generated for hidden class378LOG0("Native Agent: FAIL: missed ClassPrepare event for hidden class\n");379failed = true;380}381return failed;382}383384} // extern "C"385386387