1 /* 2 * Copyright (c) 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #include <stdlib.h> 27 #include <assert.h> 28 29 #include "jni.h" 30 #include "jni_util.h" 31 #include "jlong.h" 32 #include "jvm.h" 33 #include "jdk_internal_loader_NativeLibraries.h" 34 #include <string.h> 35 36 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *); 37 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *); 38 39 static jfieldID handleID; 40 static jfieldID jniVersionID; 41 static void *procHandle; 42 43 44 static jboolean initIDs(JNIEnv *env) 45 { 46 if (handleID == 0) { 47 jclass this = 48 (*env)->FindClass(env, "jdk/internal/loader/NativeLibraries$NativeLibraryImpl"); 49 if (this == 0) 50 return JNI_FALSE; 51 handleID = (*env)->GetFieldID(env, this, "handle", "J"); 52 if (handleID == 0) 53 return JNI_FALSE; 54 jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I"); 55 if (jniVersionID == 0) 56 return JNI_FALSE; 57 procHandle = getProcessHandle(); 58 } 59 return JNI_TRUE; 60 } 61 62 63 /* 64 * Support for finding JNI_On(Un)Load_<lib_name> if it exists. 65 * If cname == NULL then just find normal JNI_On(Un)Load entry point 66 */ 67 static void *findJniFunction(JNIEnv *env, void *handle, 68 const char *cname, jboolean isLoad) { 69 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 70 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 71 const char **syms; 72 int symsLen; 73 void *entryName = NULL; 74 char *jniFunctionName; 75 int i; 76 size_t len; 77 78 // Check for JNI_On(Un)Load<_libname> function 79 if (isLoad) { 80 syms = onLoadSymbols; 81 symsLen = sizeof(onLoadSymbols) / sizeof(char *); 82 } else { 83 syms = onUnloadSymbols; 84 symsLen = sizeof(onUnloadSymbols) / sizeof(char *); 85 } 86 for (i = 0; i < symsLen; i++) { 87 // cname + sym + '_' + '\0' 88 if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) > 89 FILENAME_MAX) { 90 goto done; 91 } 92 jniFunctionName = malloc(len); 93 if (jniFunctionName == NULL) { 94 JNU_ThrowOutOfMemoryError(env, NULL); 95 goto done; 96 } 97 buildJniFunctionName(syms[i], cname, jniFunctionName); 98 entryName = JVM_FindLibraryEntry(handle, jniFunctionName); 99 free(jniFunctionName); 100 if(entryName) { 101 break; 102 } 103 } 104 105 done: 106 return entryName; 107 } 108 109 /* 110 * Class: jdk_internal_loader_NativeLibraries 111 * Method: load 112 * Signature: (Ljava/lang/String;Z)Z 113 */ 114 JNIEXPORT jboolean JNICALL 115 Java_jdk_internal_loader_NativeLibraries_load 116 (JNIEnv *env, jobject this, jobject lib, jstring name, jboolean isBuiltin) 117 { 118 const char *cname; 119 jint jniVersion; 120 jthrowable cause; 121 void * handle; 122 jboolean loaded = JNI_FALSE; 123 124 if (!initIDs(env)) 125 return JNI_FALSE; 126 127 cname = JNU_GetStringPlatformChars(env, name, 0); 128 if (cname == 0) 129 return JNI_FALSE; 130 handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); 131 if (handle) { 132 JNI_OnLoad_t JNI_OnLoad; 133 JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle, 134 isBuiltin ? cname : NULL, 135 JNI_TRUE); 136 if (JNI_OnLoad) { 137 JavaVM *jvm; 138 (*env)->GetJavaVM(env, &jvm); 139 jniVersion = (*JNI_OnLoad)(jvm, NULL); 140 } else { 141 jniVersion = 0x00010001; 142 } 143 144 cause = (*env)->ExceptionOccurred(env); 145 if (cause) { 146 (*env)->ExceptionClear(env); 147 (*env)->Throw(env, cause); 148 if (!isBuiltin) { 149 JVM_UnloadLibrary(handle); 150 } 151 goto done; 152 } 153 154 if (!JVM_IsSupportedJNIVersion(jniVersion) || 155 (isBuiltin && jniVersion < JNI_VERSION_1_8)) { 156 char msg[256]; 157 jio_snprintf(msg, sizeof(msg), 158 "unsupported JNI version 0x%08X required by %s", 159 jniVersion, cname); 160 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); 161 if (!isBuiltin) { 162 JVM_UnloadLibrary(handle); 163 } 164 goto done; 165 } 166 (*env)->SetIntField(env, lib, jniVersionID, jniVersion); 167 } else { 168 cause = (*env)->ExceptionOccurred(env); 169 if (cause) { 170 (*env)->ExceptionClear(env); 171 (*env)->SetLongField(env, lib, handleID, (jlong)0); 172 (*env)->Throw(env, cause); 173 } 174 goto done; 175 } 176 (*env)->SetLongField(env, lib, handleID, ptr_to_jlong(handle)); 177 loaded = JNI_TRUE; 178 179 done: 180 JNU_ReleaseStringPlatformChars(env, name, cname); 181 return loaded; 182 } 183 184 /* 185 * Class: jdk_internal_loader_NativeLibraries 186 * Method: unload 187 * Signature: (Ljava/lang/String;ZJ)V 188 */ 189 JNIEXPORT void JNICALL 190 Java_jdk_internal_loader_NativeLibraries_unload 191 (JNIEnv *env, jclass cls, jstring name, jboolean isBuiltin, jlong address) 192 { 193 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 194 void *handle; 195 JNI_OnUnload_t JNI_OnUnload; 196 const char *cname; 197 198 if (!initIDs(env)) 199 return; 200 cname = JNU_GetStringPlatformChars(env, name, 0); 201 if (cname == NULL) { 202 return; 203 } 204 handle = jlong_to_ptr(address); 205 JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle, 206 isBuiltin ? cname : NULL, 207 JNI_FALSE); 208 if (JNI_OnUnload) { 209 JavaVM *jvm; 210 (*env)->GetJavaVM(env, &jvm); 211 (*JNI_OnUnload)(jvm, NULL); 212 } 213 if (!isBuiltin) { 214 JVM_UnloadLibrary(handle); 215 } 216 JNU_ReleaseStringPlatformChars(env, name, cname); 217 } 218 219 220 /* 221 * Class: jdk_internal_loader_NativeLibraries 222 * Method: findEntry0 223 * Signature: (Ljava/lang/String;)J 224 */ 225 JNIEXPORT jlong JNICALL 226 Java_jdk_internal_loader_NativeLibraries_findEntry0 227 (JNIEnv *env, jobject this, jobject lib, jstring name) 228 { 229 jlong handle; 230 const char *cname; 231 jlong res; 232 233 if (!initIDs(env)) 234 return jlong_zero; 235 236 handle = (*env)->GetLongField(env, lib, handleID); 237 cname = (*env)->GetStringUTFChars(env, name, 0); 238 if (cname == 0) 239 return jlong_zero; 240 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname)); 241 (*env)->ReleaseStringUTFChars(env, name, cname); 242 return res; 243 } 244 245 /* 246 * Class: jdk_internal_loader_NativeLibraries 247 * Method: findBuiltinLib 248 * Signature: (Ljava/lang/String;)Ljava/lang/String; 249 */ 250 JNIEXPORT jstring JNICALL 251 Java_jdk_internal_loader_NativeLibraries_findBuiltinLib 252 (JNIEnv *env, jclass cls, jstring name) 253 { 254 const char *cname; 255 char *libName; 256 size_t prefixLen = strlen(JNI_LIB_PREFIX); 257 size_t suffixLen = strlen(JNI_LIB_SUFFIX); 258 size_t len; 259 jstring lib; 260 void *ret; 261 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 262 263 if (name == NULL) { 264 JNU_ThrowInternalError(env, "NULL filename for native library"); 265 return NULL; 266 } 267 procHandle = getProcessHandle(); 268 cname = JNU_GetStringPlatformChars(env, name, 0); 269 if (cname == NULL) { 270 return NULL; 271 } 272 // Copy name Skipping PREFIX 273 len = strlen(cname); 274 if (len <= (prefixLen+suffixLen)) { 275 JNU_ReleaseStringPlatformChars(env, name, cname); 276 return NULL; 277 } 278 libName = malloc(len + 1); //+1 for null if prefix+suffix == 0 279 if (libName == NULL) { 280 JNU_ReleaseStringPlatformChars(env, name, cname); 281 JNU_ThrowOutOfMemoryError(env, NULL); 282 return NULL; 283 } 284 if (len > prefixLen) { 285 strcpy(libName, cname+prefixLen); 286 } 287 JNU_ReleaseStringPlatformChars(env, name, cname); 288 289 // Strip SUFFIX 290 libName[strlen(libName)-suffixLen] = '\0'; 291 292 // Check for JNI_OnLoad_libname function 293 ret = findJniFunction(env, procHandle, libName, JNI_TRUE); 294 if (ret != NULL) { 295 lib = JNU_NewStringPlatform(env, libName); 296 free(libName); 297 return lib; 298 } 299 free(libName); 300 return NULL; 301 } 302 303