1/* 2 * Copyright (c) 2016, 2017, 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 <stdio.h> 25#include <string.h> 26#include "jvmti.h" 27 28#ifdef __cplusplus 29extern "C" { 30#endif 31 32#ifndef JNI_ENV_ARG 33 34#ifdef __cplusplus 35#define JNI_ENV_ARG(x, y) y 36#define JNI_ENV_PTR(x) x 37#else 38#define JNI_ENV_ARG(x,y) x, y 39#define JNI_ENV_PTR(x) (*x) 40#endif 41 42#endif 43 44#define TranslateError(err) "JVMTI error" 45 46#define PASSED 0 47#define FAILED 2 48 49static const char *EXC_CNAME = "java/lang/Exception"; 50static const char* MOD_CNAME = "Ljava/lang/Module;"; 51 52static jvmtiEnv *jvmti = NULL; 53static jint result = PASSED; 54 55static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved); 56 57JNIEXPORT 58jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) { 59 return Agent_Initialize(jvm, options, reserved); 60} 61 62JNIEXPORT 63jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) { 64 return Agent_Initialize(jvm, options, reserved); 65} 66 67JNIEXPORT 68jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) { 69 return JNI_VERSION_1_8; 70} 71 72static 73jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) { 74 jint res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti), 75 JVMTI_VERSION_9); 76 if (res != JNI_OK || jvmti == NULL) { 77 printf(" Error: wrong result of a valid call to GetEnv!\n"); 78 return JNI_ERR; 79 } 80 81 return JNI_OK; 82} 83 84static 85void throw_exc(JNIEnv *env, char *msg) { 86 jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME)); 87 jint rt = JNI_OK; 88 89 if (exc_class == NULL) { 90 printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME); 91 return; 92 } 93 rt = JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg); 94 if (rt == JNI_ERR) { 95 printf("throw_exc: Error in JNI ThrowNew(env, %s)\n", msg); 96 } 97} 98 99static 100jclass jlM(JNIEnv *env) { 101 jclass cls = NULL; 102 103 cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, MOD_CNAME)); 104 if (cls == NULL) { 105 printf(" Error in JNI FindClass: %s\n", MOD_CNAME); 106 } 107 return cls; 108} 109 110jmethodID 111get_method(JNIEnv *env, jclass clazz, const char * name, const char *sig) { 112 jmethodID method = NULL; 113 114 method = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG(env, clazz), name, sig); 115 if (method == NULL) { 116 printf(" Error in JNI GetMethodID %s with signature %s", name, sig); 117 } 118 return method; 119} 120 121static 122jboolean is_exported(JNIEnv *env, jobject module, const char* pkg, jboolean open) { 123 static jmethodID mIsExported = NULL; 124 jstring jstr = NULL; 125 jboolean res = JNI_FALSE; 126 127 if (mIsExported == NULL) { 128 const char* sign = "(Ljava/lang/String;)Z"; 129 const char* name = open ? "isOpen" : "isExported"; 130 mIsExported = get_method(env, jlM(env), name, sign); 131 } 132 jstr = JNI_ENV_PTR(env)->NewStringUTF(JNI_ENV_ARG(env, pkg)); 133 res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module), 134 mIsExported, jstr); 135 return res; 136} 137 138static 139jboolean is_exported_to(JNIEnv *env, jobject module, const char* pkg, jobject to_module, 140 jboolean open) { 141 static jmethodID mIsExportedTo = NULL; 142 jstring jstr = NULL; 143 jboolean res = JNI_FALSE; 144 145 if (mIsExportedTo == NULL) { 146 const char* sign = "(Ljava/lang/String;Ljava/lang/Module;)Z"; 147 const char* name = open ? "isOpen" : "isExported"; 148 mIsExportedTo = get_method(env, jlM(env), name, sign); 149 } 150 jstr = JNI_ENV_PTR(env)->NewStringUTF(JNI_ENV_ARG(env, pkg)); 151 res = JNI_ENV_PTR(env)->CallBooleanMethod(JNI_ENV_ARG(env, module), 152 mIsExportedTo, jstr, to_module); 153 return res; 154} 155 156static 157jvmtiError add_module_exports(jobject baseModule, const char* pkg, jobject thisModule, 158 jboolean open) { 159 jvmtiError err = JVMTI_ERROR_NONE; 160 if (open) { 161 err = (*jvmti)->AddModuleOpens(jvmti, baseModule, pkg, thisModule); 162 } else { 163 err = (*jvmti)->AddModuleExports(jvmti, baseModule, pkg, thisModule); 164 } 165 return err; 166} 167 168static 169jint check_add_module_exports(JNIEnv *env, 170 jclass cls, 171 jobject baseModule, 172 jobject thisModule, 173 jboolean open) { 174 static char strbuf[128] = { '\0' }; 175 jvmtiError err = JVMTI_ERROR_NONE; 176 const char* pkg = open ? "jdk.internal.math" 177 : "jdk.internal.misc"; 178 const char* bad_pkg = "my.bad.pkg"; 179 const char* jvmti_fn = open ? "AddModuleOpens" 180 : "AddModuleExports"; 181 jboolean exported = JNI_FALSE; 182 183 // Export from NULL module 184 printf("Check #N1:\n"); 185 err = add_module_exports(NULL, pkg, thisModule, open); 186 if (err != JVMTI_ERROR_NULL_POINTER) { 187 printf("#N1: jvmtiError from %s: %d\n", jvmti_fn, err); 188 throw_exc(env, "Check #N1: failed to return JVMTI_ERROR_NULL_POINTER for module==NULL"); 189 return FAILED; 190 } 191 192 // Export NULL package 193 printf("Check #N2:\n"); 194 err = add_module_exports(baseModule, NULL, thisModule, open); 195 if (err != JVMTI_ERROR_NULL_POINTER) { 196 printf("#N2: jvmtiError from %s: %d\n", jvmti_fn, err); 197 throw_exc(env, "Check #N2: failed to return JVMTI_ERROR_NULL_POINTER for pkg==NULL"); 198 return FAILED; 199 } 200 201 // Export to NULL module 202 printf("Check #N3:\n"); 203 err = add_module_exports(baseModule, pkg, NULL, open); 204 if (err != JVMTI_ERROR_NULL_POINTER) { 205 printf("#N3: jvmtiError from %s: %d\n", jvmti_fn, err); 206 throw_exc(env, "Check #N3: failed to return JVMTI_ERROR_NULL_POINTER for to_module==NULL"); 207 return FAILED; 208 } 209 210 // Export a bad package 211 printf("Check #I0:\n"); 212 err = add_module_exports(baseModule, bad_pkg, thisModule, open); 213 if (err != JVMTI_ERROR_ILLEGAL_ARGUMENT) { 214 printf("#I0: jvmtiError from %s: %d\n", jvmti_fn, err); 215 throw_exc(env, "Check #I0: did not get expected JVMTI_ERROR_ILLEGAL_ARGUMENT for invalid package"); 216 return FAILED; 217 } 218 219 // Export from invalid module (cls) 220 printf("Check #I1:\n"); 221 err = add_module_exports((jobject)cls, pkg, thisModule, open); 222 if (err != JVMTI_ERROR_INVALID_MODULE) { 223 printf("#I1: jvmtiError from %s: %d\n", jvmti_fn, err); 224 throw_exc(env, "Check #I1: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid module"); 225 return FAILED; 226 } 227 228 // Export to invalid module (cls) 229 printf("Check #I2:\n"); 230 err = add_module_exports(baseModule, pkg, (jobject)cls, open); 231 if (err != JVMTI_ERROR_INVALID_MODULE) { 232 printf("#I2: jvmtiError from %s: %d\n", jvmti_fn, err); 233 throw_exc(env, "Check #I2: did not get expected JVMTI_ERROR_INVALID_MODULE for invalid to_module"); 234 return FAILED; 235 } 236 237 // Check the pkg is not exported from baseModule to thisModule 238 printf("Check #C0:\n"); 239 exported = is_exported_to(env, baseModule, pkg, thisModule, open); 240 if (exported != JNI_FALSE) { 241 sprintf(strbuf, "Check #C0: unexpected export of %s from base to this", pkg); 242 throw_exc(env, strbuf); 243 return FAILED; 244 } 245 246 // Add export of the pkg from baseModule to thisModule 247 printf("Check #C1:\n"); 248 err = add_module_exports(baseModule, pkg, thisModule, open); 249 if (err != JVMTI_ERROR_NONE) { 250 printf("#C1: jvmtiError from %s: %d\n", jvmti_fn, err); 251 sprintf(strbuf, "Check #C1: error in add export of %s from base to this", pkg); 252 throw_exc(env, strbuf); 253 return FAILED; 254 } 255 256 // Check the pkg is exported from baseModule to thisModule 257 printf("Check #C2:\n"); 258 exported = is_exported_to(env, baseModule, pkg, thisModule, open); 259 if (exported == JNI_FALSE) { 260 sprintf(strbuf, "Check #C2: failed to export %s from base to this", pkg); 261 throw_exc(env, strbuf); 262 return FAILED; 263 } 264 265 // Check the pkg is not exported to all modules 266 printf("Check #C3:\n"); 267 exported = is_exported(env, baseModule, pkg, open); 268 if (exported != JNI_FALSE) { 269 sprintf(strbuf, "Check #C3: unexpected export of %s from base to all modules", pkg); 270 throw_exc(env, strbuf); 271 return FAILED; 272 } 273 return PASSED; 274} 275 276JNIEXPORT jint JNICALL 277Java_MyPackage_AddModuleExportsAndOpensTest_check(JNIEnv *env, 278 jclass cls, 279 jobject baseModule, 280 jobject thisModule) { 281 if (jvmti == NULL) { 282 throw_exc(env, "JVMTI client was not properly loaded!\n"); 283 return FAILED; 284 } 285 286 printf("\n*** Checks for JVMTI AddModuleExports ***\n\n"); 287 result = check_add_module_exports(env, cls, baseModule, thisModule, JNI_FALSE); 288 if (result != PASSED) { 289 return result; 290 } 291 292 printf("\n*** Checks for JVMTI AddModuleOpens ***\n\n"); 293 result = check_add_module_exports(env, cls, baseModule, thisModule, JNI_TRUE); 294 if (result != PASSED) { 295 return result; 296 } 297 return result; 298} 299 300#ifdef __cplusplus 301} 302#endif 303