1 /* 2 * Copyright (c) 1996, 2015, 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 "check_classname.h" 34 #include "java_lang_ClassLoader.h" 35 #include "java_lang_ClassLoader_NativeLibrary.h" 36 #include <string.h> 37 38 static JNINativeMethod methods[] = { 39 {"retrieveDirectives", "()Ljava/lang/AssertionStatusDirectives;", (void *)&JVM_AssertionStatusDirectives} 40 }; 41 42 JNIEXPORT void JNICALL 43 Java_java_lang_ClassLoader_registerNatives(JNIEnv *env, jclass cls) 44 { 45 (*env)->RegisterNatives(env, cls, methods, 46 sizeof(methods)/sizeof(JNINativeMethod)); 47 } 48 49 /* Convert java string to UTF char*. Use local buffer if possible, 50 otherwise malloc new memory. Returns null IFF malloc failed. */ 51 static char* 52 getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize) 53 { 54 char* utfStr = NULL; 55 56 int len = (*env)->GetStringUTFLength(env, str); 57 int unicode_len = (*env)->GetStringLength(env, str); 58 if (len >= bufSize) { 59 utfStr = malloc(len + 1); 60 if (utfStr == NULL) { 61 JNU_ThrowOutOfMemoryError(env, NULL); 62 return NULL; 63 } 64 } else { 65 utfStr = localBuf; 66 } 67 (*env)->GetStringUTFRegion(env, str, 0, unicode_len, utfStr); 68 69 return utfStr; 70 } 71 72 JNIEXPORT jclass JNICALL 73 Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, 74 jclass cls, 75 jobject loader, 76 jstring name, 77 jbyteArray data, 78 jint offset, 79 jint length, 80 jobject pd, 81 jstring source) 82 { 83 jbyte *body; 84 char *utfName; 85 jclass result = 0; 86 char buf[128]; 87 char* utfSource; 88 char sourceBuf[1024]; 89 90 if (data == NULL) { 91 JNU_ThrowNullPointerException(env, 0); 92 return 0; 93 } 94 95 /* Work around 4153825. malloc crashes on Solaris when passed a 96 * negative size. 97 */ 98 if (length < 0) { 99 JNU_ThrowArrayIndexOutOfBoundsException(env, 0); 100 return 0; 101 } 102 103 body = (jbyte *)malloc(length); 104 105 if (body == 0) { 106 JNU_ThrowOutOfMemoryError(env, 0); 107 return 0; 108 } 109 110 (*env)->GetByteArrayRegion(env, data, offset, length, body); 111 112 if ((*env)->ExceptionOccurred(env)) 113 goto free_body; 114 115 if (name != NULL) { 116 utfName = getUTF(env, name, buf, sizeof(buf)); 117 if (utfName == NULL) { 118 goto free_body; 119 } 120 fixClassname(utfName); 121 } else { 122 utfName = NULL; 123 } 124 125 if (source != NULL) { 126 utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf)); 127 if (utfSource == NULL) { 128 goto free_utfName; 129 } 130 } else { 131 utfSource = NULL; 132 } 133 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); 134 135 if (utfSource && utfSource != sourceBuf) 136 free(utfSource); 137 138 free_utfName: 139 if (utfName && utfName != buf) 140 free(utfName); 141 142 free_body: 143 free(body); 144 return result; 145 } 146 147 JNIEXPORT jclass JNICALL 148 Java_java_lang_ClassLoader_defineClass2(JNIEnv *env, 149 jclass cls, 150 jobject loader, 151 jstring name, 152 jobject data, 153 jint offset, 154 jint length, 155 jobject pd, 156 jstring source) 157 { 158 jbyte *body; 159 char *utfName; 160 jclass result = 0; 161 char buf[128]; 162 char* utfSource; 163 char sourceBuf[1024]; 164 165 assert(data != NULL); // caller fails if data is null. 166 assert(length >= 0); // caller passes ByteBuffer.remaining() for length, so never neg. 167 // caller passes ByteBuffer.position() for offset, and capacity() >= position() + remaining() 168 assert((*env)->GetDirectBufferCapacity(env, data) >= (offset + length)); 169 170 body = (*env)->GetDirectBufferAddress(env, data); 171 172 if (body == 0) { 173 JNU_ThrowNullPointerException(env, 0); 174 return 0; 175 } 176 177 body += offset; 178 179 if (name != NULL) { 180 utfName = getUTF(env, name, buf, sizeof(buf)); 181 if (utfName == NULL) { 182 JNU_ThrowOutOfMemoryError(env, NULL); 183 return result; 184 } 185 fixClassname(utfName); 186 } else { 187 utfName = NULL; 188 } 189 190 if (source != NULL) { 191 utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf)); 192 if (utfSource == NULL) { 193 JNU_ThrowOutOfMemoryError(env, NULL); 194 goto free_utfName; 195 } 196 } else { 197 utfSource = NULL; 198 } 199 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); 200 201 if (utfSource && utfSource != sourceBuf) 202 free(utfSource); 203 204 free_utfName: 205 if (utfName && utfName != buf) 206 free(utfName); 207 208 return result; 209 } 210 211 /* 212 * Returns NULL if class not found. 213 */ 214 JNIEXPORT jclass JNICALL 215 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, 216 jstring classname) 217 { 218 char *clname; 219 jclass cls = 0; 220 char buf[128]; 221 222 if (classname == NULL) { 223 return 0; 224 } 225 226 clname = getUTF(env, classname, buf, sizeof(buf)); 227 if (clname == NULL) { 228 JNU_ThrowOutOfMemoryError(env, NULL); 229 return NULL; 230 } 231 fixClassname(clname); 232 233 if (!verifyClassname(clname, JNI_TRUE)) { /* expects slashed name */ 234 goto done; 235 } 236 237 cls = JVM_FindClassFromBootLoader(env, clname); 238 239 done: 240 if (clname != buf) { 241 free(clname); 242 } 243 244 return cls; 245 } 246 247 JNIEXPORT jclass JNICALL 248 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader, 249 jstring name) 250 { 251 if (name == NULL) { 252 return 0; 253 } else { 254 return JVM_FindLoadedClass(env, loader, name); 255 } 256 } 257 258 static jfieldID handleID; 259 static jfieldID jniVersionID; 260 static void *procHandle; 261 262 static jboolean initIDs(JNIEnv *env) 263 { 264 if (handleID == 0) { 265 jclass this = 266 (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary"); 267 if (this == 0) 268 return JNI_FALSE; 269 handleID = (*env)->GetFieldID(env, this, "handle", "J"); 270 if (handleID == 0) 271 return JNI_FALSE; 272 jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I"); 273 if (jniVersionID == 0) 274 return JNI_FALSE; 275 procHandle = getProcessHandle(); 276 } 277 return JNI_TRUE; 278 } 279 280 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *); 281 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *); 282 283 /* 284 * Support for finding JNI_On(Un)Load_<lib_name> if it exists. 285 * If cname == NULL then just find normal JNI_On(Un)Load entry point 286 */ 287 static void *findJniFunction(JNIEnv *env, void *handle, 288 const char *cname, jboolean isLoad) { 289 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 290 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 291 const char **syms; 292 int symsLen; 293 void *entryName = NULL; 294 char *jniFunctionName; 295 int i; 296 size_t len; 297 298 // Check for JNI_On(Un)Load<_libname> function 299 if (isLoad) { 300 syms = onLoadSymbols; 301 symsLen = sizeof(onLoadSymbols) / sizeof(char *); 302 } else { 303 syms = onUnloadSymbols; 304 symsLen = sizeof(onUnloadSymbols) / sizeof(char *); 305 } 306 for (i = 0; i < symsLen; i++) { 307 // cname + sym + '_' + '\0' 308 if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) > 309 FILENAME_MAX) { 310 goto done; 311 } 312 jniFunctionName = malloc(len); 313 if (jniFunctionName == NULL) { 314 JNU_ThrowOutOfMemoryError(env, NULL); 315 goto done; 316 } 317 buildJniFunctionName(syms[i], cname, jniFunctionName); 318 entryName = JVM_FindLibraryEntry(handle, jniFunctionName); 319 free(jniFunctionName); 320 if(entryName) { 321 break; 322 } 323 } 324 325 done: 326 return entryName; 327 } 328 329 /* 330 * Class: java_lang_ClassLoader_NativeLibrary 331 * Method: load0 332 * Signature: (Ljava/lang/String;Z)Z 333 */ 334 JNIEXPORT jboolean JNICALL 335 Java_java_lang_ClassLoader_00024NativeLibrary_load0 336 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 337 { 338 const char *cname; 339 jint jniVersion; 340 jthrowable cause; 341 void * handle; 342 jboolean loaded = JNI_FALSE; 343 344 if (!initIDs(env)) 345 return JNI_FALSE; 346 347 cname = JNU_GetStringPlatformChars(env, name, 0); 348 if (cname == 0) 349 return JNI_FALSE; 350 handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); 351 if (handle) { 352 JNI_OnLoad_t JNI_OnLoad; 353 JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle, 354 isBuiltin ? cname : NULL, 355 JNI_TRUE); 356 if (JNI_OnLoad) { 357 JavaVM *jvm; 358 (*env)->GetJavaVM(env, &jvm); 359 jniVersion = (*JNI_OnLoad)(jvm, NULL); 360 } else { 361 jniVersion = 0x00010001; 362 } 363 364 cause = (*env)->ExceptionOccurred(env); 365 if (cause) { 366 (*env)->ExceptionClear(env); 367 (*env)->Throw(env, cause); 368 if (!isBuiltin) { 369 JVM_UnloadLibrary(handle); 370 } 371 goto done; 372 } 373 374 if (!JVM_IsSupportedJNIVersion(jniVersion) || 375 (isBuiltin && jniVersion < JNI_VERSION_1_8)) { 376 char msg[256]; 377 jio_snprintf(msg, sizeof(msg), 378 "unsupported JNI version 0x%08X required by %s", 379 jniVersion, cname); 380 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); 381 if (!isBuiltin) { 382 JVM_UnloadLibrary(handle); 383 } 384 goto done; 385 } 386 (*env)->SetIntField(env, this, jniVersionID, jniVersion); 387 } else { 388 cause = (*env)->ExceptionOccurred(env); 389 if (cause) { 390 (*env)->ExceptionClear(env); 391 (*env)->SetLongField(env, this, handleID, (jlong)0); 392 (*env)->Throw(env, cause); 393 } 394 goto done; 395 } 396 (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); 397 loaded = JNI_TRUE; 398 399 done: 400 JNU_ReleaseStringPlatformChars(env, name, cname); 401 return loaded; 402 } 403 404 /* 405 * Class: java_lang_ClassLoader_NativeLibrary 406 * Method: unload 407 * Signature: (Ljava/lang/String;ZJ)V 408 */ 409 JNIEXPORT void JNICALL 410 Java_java_lang_ClassLoader_00024NativeLibrary_unload 411 (JNIEnv *env, jclass cls, jstring name, jboolean isBuiltin, jlong address) 412 { 413 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 414 void *handle; 415 JNI_OnUnload_t JNI_OnUnload; 416 const char *cname; 417 418 if (!initIDs(env)) 419 return; 420 cname = JNU_GetStringPlatformChars(env, name, 0); 421 if (cname == NULL) { 422 return; 423 } 424 handle = jlong_to_ptr(address); 425 JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle, 426 isBuiltin ? cname : NULL, 427 JNI_FALSE); 428 if (JNI_OnUnload) { 429 JavaVM *jvm; 430 (*env)->GetJavaVM(env, &jvm); 431 (*JNI_OnUnload)(jvm, NULL); 432 } 433 if (!isBuiltin) { 434 JVM_UnloadLibrary(handle); 435 } 436 JNU_ReleaseStringPlatformChars(env, name, cname); 437 } 438 439 /* 440 * Class: java_lang_ClassLoader_NativeLibrary 441 * Method: findEntry 442 * Signature: (Ljava/lang/String;)J 443 */ 444 JNIEXPORT jlong JNICALL 445 Java_java_lang_ClassLoader_00024NativeLibrary_findEntry 446 (JNIEnv *env, jobject this, jstring name) 447 { 448 jlong handle; 449 const char *cname; 450 jlong res; 451 452 if (!initIDs(env)) 453 return jlong_zero; 454 455 handle = (*env)->GetLongField(env, this, handleID); 456 cname = (*env)->GetStringUTFChars(env, name, 0); 457 if (cname == 0) 458 return jlong_zero; 459 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname)); 460 (*env)->ReleaseStringUTFChars(env, name, cname); 461 return res; 462 } 463 /* 464 * Class: java_lang_ClassLoader 465 * Method: findBuiltinLib 466 * Signature: (Ljava/lang/String;)Ljava/lang/String; 467 */ 468 JNIEXPORT jstring JNICALL 469 Java_java_lang_ClassLoader_findBuiltinLib 470 (JNIEnv *env, jclass cls, jstring name) 471 { 472 const char *cname; 473 char *libName; 474 size_t prefixLen = strlen(JNI_LIB_PREFIX); 475 size_t suffixLen = strlen(JNI_LIB_SUFFIX); 476 size_t len; 477 jstring lib; 478 void *ret; 479 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 480 481 if (name == NULL) { 482 JNU_ThrowInternalError(env, "NULL filename for native library"); 483 return NULL; 484 } 485 procHandle = getProcessHandle(); 486 cname = JNU_GetStringPlatformChars(env, name, 0); 487 if (cname == NULL) { 488 return NULL; 489 } 490 // Copy name Skipping PREFIX 491 len = strlen(cname); 492 if (len <= (prefixLen+suffixLen)) { 493 JNU_ReleaseStringPlatformChars(env, name, cname); 494 return NULL; 495 } 496 libName = malloc(len + 1); //+1 for null if prefix+suffix == 0 497 if (libName == NULL) { 498 JNU_ReleaseStringPlatformChars(env, name, cname); 499 JNU_ThrowOutOfMemoryError(env, NULL); 500 return NULL; 501 } 502 if (len > prefixLen) { 503 strcpy(libName, cname+prefixLen); 504 } 505 JNU_ReleaseStringPlatformChars(env, name, cname); 506 507 // Strip SUFFIX 508 libName[strlen(libName)-suffixLen] = '\0'; 509 510 // Check for JNI_OnLoad_libname function 511 ret = findJniFunction(env, procHandle, libName, JNI_TRUE); 512 if (ret != NULL) { 513 lib = JNU_NewStringPlatform(env, libName); 514 free(libName); 515 return lib; 516 } 517 free(libName); 518 return NULL; 519 }