1 /* 2 * Copyright (c) 2019, 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 <stdlib.h> 26 27 #include "jni.h" 28 #include "assert.h" 29 #ifndef WIN32 30 #include "pthread.h" 31 #endif 32 33 static jclass classClass; 34 static jclass iaeClass; 35 static jmethodID mid_Class_forName; 36 static jmethodID mid_Class_getField; 37 static jmethodID mid_Field_get; 38 39 int getField(JNIEnv *env, char* declaringClass_name, char* field_name); 40 int checkAndClearIllegalAccessExceptionThrown(JNIEnv *env); 41 42 static int main_inner(int argc, char** args) { 43 JavaVM *jvm; 44 JNIEnv *env; 45 JavaVMInitArgs vm_args; 46 JavaVMOption options[1]; 47 jint rc; 48 49 vm_args.version = JNI_VERSION_1_2; 50 vm_args.nOptions = 0; 51 vm_args.options = options; 52 53 if ((rc = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args)) != JNI_OK) { 54 printf("ERROR: cannot create VM.\n"); 55 exit(-1); 56 } 57 58 classClass = (*env)->FindClass(env, "java/lang/Class"); 59 iaeClass = (*env)->FindClass(env, "java/lang/IllegalAccessException"); 60 mid_Class_forName = (*env)->GetStaticMethodID(env, classClass, "forName", 61 "(Ljava/lang/String;)Ljava/lang/Class;"); 62 assert(mid_Class_forName != NULL); 63 64 mid_Class_getField = (*env)->GetMethodID(env, classClass, "getField", 65 "(Ljava/lang/String;)Ljava/lang/reflect/Field;"); 66 assert(mid_Class_getField != NULL); 67 68 jclass fieldClass = (*env)->FindClass(env, "java/lang/reflect/Field"); 69 mid_Field_get = (*env)->GetMethodID(env, fieldClass, "get", "(Ljava/lang/Object;)Ljava/lang/Object;"); 70 assert(mid_Class_getField != NULL); 71 72 // can access to public member of an exported type 73 if ((rc = getField(env, "java.lang.Integer", "TYPE")) != 0) { 74 printf("ERROR: fail to access java.lang.Integer::TYPE\n"); 75 exit(-1); 76 } 77 78 // expect IAE to jdk.internal.misc.Unsafe class 79 if ((rc = getField(env, "jdk.internal.misc.Unsafe", "INVALID_FIELD_OFFSET")) == 0) { 80 printf("ERROR: IAE not thrown\n"); 81 exit(-1); 82 } 83 if (checkAndClearIllegalAccessExceptionThrown(env) != JNI_TRUE) { 84 printf("ERROR: exception is not an instance of IAE\n"); 85 exit(-1); 86 } 87 88 // expect IAE to jdk.internal.misc.Unsafe class 89 if ((rc = getField(env, "jdk.internal.misc.Unsafe", "INVALID_FIELD_OFFSET")) == 0) { 90 printf("ERROR: IAE not thrown\n"); 91 exit(-1); 92 } 93 if (checkAndClearIllegalAccessExceptionThrown(env) != JNI_TRUE) { 94 printf("ERROR: exception is not an instance of IAE\n"); 95 exit(-1); 96 } 97 98 (*jvm)->DestroyJavaVM(jvm); 99 return 0; 100 } 101 102 int checkAndClearIllegalAccessExceptionThrown(JNIEnv *env) { 103 jthrowable t = (*env)->ExceptionOccurred(env); 104 if ((*env)->IsInstanceOf(env, t, iaeClass) == JNI_TRUE) { 105 (*env)->ExceptionClear(env); 106 return JNI_TRUE; 107 } 108 return JNI_FALSE; 109 } 110 111 int getField(JNIEnv *env, char* declaringClass_name, char* field_name) { 112 jobject c = (*env)->CallStaticObjectMethod(env, classClass, mid_Class_forName, 113 (*env)->NewStringUTF(env, declaringClass_name)); 114 if ((*env)->ExceptionOccurred(env) != NULL) { 115 (*env)->ExceptionDescribe(env); 116 return 1; 117 } 118 119 jobject f = (*env)->CallObjectMethod(env, c, mid_Class_getField, (*env)->NewStringUTF(env, field_name)); 120 if ((*env)->ExceptionOccurred(env) != NULL) { 121 (*env)->ExceptionDescribe(env); 122 return 2; 123 } 124 125 jobject v = (*env)->CallObjectMethod(env, f, mid_Field_get, c); 126 if ((*env)->ExceptionOccurred(env) != NULL) { 127 (*env)->ExceptionDescribe(env); 128 return 3; 129 } 130 return 0; 131 } 132 133 /* On AIX, unfortunately, we are not able to invoke the libjvm on the primordial thread. */ 134 135 #ifdef _AIX 136 #define DEFAULT_SPAWN_IN_NEW_THREAD 137 #else 138 #undef DEFAULT_SPAWN_IN_NEW_THREAD 139 #endif 140 141 struct args_t { 142 int argc; char** argv; 143 }; 144 145 #define STACK_SIZE 0x200000 146 147 #ifdef _WIN32 148 149 #error Not implemented on Windows. 150 151 #else 152 153 static void* thread_wrapper(void* p) { 154 const struct args_t* const p_args = (const struct args_t*) p; 155 main_inner(p_args->argc, p_args->argv); 156 return 0; 157 } 158 159 static void run_in_new_thread(const struct args_t* args) { 160 pthread_t tid; 161 pthread_attr_t attr; 162 163 pthread_attr_init(&attr); 164 pthread_attr_setstacksize(&attr, STACK_SIZE); 165 166 if (pthread_create(&tid, &attr, thread_wrapper, (void*)args) != 0) { 167 fprintf(stderr, "Failed to create main thread\n"); 168 exit(2); 169 } 170 171 if (pthread_join(tid, NULL) != 0) { 172 fprintf(stderr, "Failed to join main thread\n"); 173 exit(2); 174 } 175 } 176 177 #endif /* ! WIN32 */ 178 179 int main(int argc, char** args) { 180 #ifdef DEFAULT_SPAWN_IN_NEW_THREAD 181 struct args_t a; 182 a.argc = argc; 183 a.argv = args; 184 run_in_new_thread(&a); 185 #else 186 main_inner(argc, args); 187 #endif 188 }