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