1 /* 2 * Copyright (c) 1996, 2010, 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 builtin library. 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 *findBuiltinJniFunction(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 *jniEntryName; 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 jniEntryName = malloc(len); 347 if (jniEntryName == NULL) { 348 JNU_ThrowOutOfMemoryError(env, NULL); 349 goto done; 350 } 351 strcpy(jniEntryName, syms[i]); 352 if (cname != NULL) { 353 strcat(jniEntryName, "_"); 354 strcat(jniEntryName, cname); 355 } 356 entryName = JVM_FindLibraryEntry(handle, jniEntryName); 357 free(jniEntryName); 358 if(entryName) { 359 break; 360 } 361 } 362 363 done: 364 return entryName; 365 } 366 367 /* 368 * Class: java_lang_ClassLoader_NativeLibrary 369 * Method: load 370 * Signature: (Ljava/lang/String;Z)V 371 */ 372 JNIEXPORT void JNICALL 373 Java_java_lang_ClassLoader_00024NativeLibrary_load 374 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 375 { 376 const char *cname; 377 jint jniVersion; 378 jthrowable cause; 379 void * handle; 380 381 if (!initIDs(env)) 382 return; 383 384 cname = JNU_GetStringPlatformChars(env, name, 0); 385 if (cname == 0) 386 return; 387 handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); 388 if (handle) { 389 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 390 JNI_OnLoad_t JNI_OnLoad; 391 JNI_OnLoad = (JNI_OnLoad_t)findBuiltinJniFunction(env, handle, 392 isBuiltin ? cname : NULL, 393 JNI_TRUE); 394 if (JNI_OnLoad) { 395 JavaVM *jvm; 396 (*env)->GetJavaVM(env, &jvm); 397 jniVersion = (*JNI_OnLoad)(jvm, NULL); 398 } else { 399 jniVersion = 0x00010001; 400 } 401 402 cause = (*env)->ExceptionOccurred(env); 403 if (cause) { 404 (*env)->ExceptionClear(env); 405 (*env)->Throw(env, cause); 406 JVM_UnloadLibrary(handle); 407 goto done; 408 } 409 410 if (!JVM_IsSupportedJNIVersion(jniVersion) || 411 (isBuiltin && jniVersion < JNI_VERSION_1_8)) { 412 char msg[256]; 413 jio_snprintf(msg, sizeof(msg), 414 "unsupported JNI version 0x%08X required by %s", 415 jniVersion, cname); 416 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); 417 JVM_UnloadLibrary(handle); 418 goto done; 419 } 420 (*env)->SetIntField(env, this, jniVersionID, jniVersion); 421 } else { 422 cause = (*env)->ExceptionOccurred(env); 423 if (cause) { 424 (*env)->ExceptionClear(env); 425 (*env)->SetLongField(env, this, handleID, (jlong)0); 426 (*env)->Throw(env, cause); 427 } 428 goto done; 429 } 430 (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); 431 (*env)->SetBooleanField(env, this, loadedID, JNI_TRUE); 432 433 done: 434 JNU_ReleaseStringPlatformChars(env, name, cname); 435 } 436 437 /* 438 * Class: java_lang_ClassLoader_NativeLibrary 439 * Method: unload 440 * Signature: (Z)V 441 */ 442 JNIEXPORT void JNICALL 443 Java_java_lang_ClassLoader_00024NativeLibrary_unload 444 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 445 { 446 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 447 void *handle; 448 JNI_OnUnload_t JNI_OnUnload; 449 const char *cname; 450 451 if (!initIDs(env)) 452 return; 453 cname = JNU_GetStringPlatformChars(env, name, 0); 454 if (cname == NULL) { 455 return; 456 } 457 handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID)); 458 JNI_OnUnload = (JNI_OnUnload_t )findBuiltinJniFunction(env, handle, 459 isBuiltin ? cname : NULL, 460 JNI_FALSE); 461 if (JNI_OnUnload) { 462 JavaVM *jvm; 463 (*env)->GetJavaVM(env, &jvm); 464 (*JNI_OnUnload)(jvm, NULL); 465 } 466 JVM_UnloadLibrary(handle); 467 JNU_ReleaseStringPlatformChars(env, name, cname); 468 } 469 470 /* 471 * Class: java_lang_ClassLoader_NativeLibrary 472 * Method: find 473 * Signature: (Ljava/lang/String;)J 474 */ 475 JNIEXPORT jlong JNICALL 476 Java_java_lang_ClassLoader_00024NativeLibrary_find 477 (JNIEnv *env, jobject this, jstring name) 478 { 479 jlong handle; 480 const char *cname; 481 jlong res; 482 483 if (!initIDs(env)) 484 return jlong_zero; 485 486 handle = (*env)->GetLongField(env, this, handleID); 487 cname = (*env)->GetStringUTFChars(env, name, 0); 488 if (cname == 0) 489 return jlong_zero; 490 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname)); 491 (*env)->ReleaseStringUTFChars(env, name, cname); 492 return res; 493 } 494 495 JNIEXPORT jobject JNICALL 496 Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index) 497 { 498 jobjectArray jcallerStack; 499 int len; 500 501 jcallerStack = JVM_GetClassContext(env); 502 if ((*env)->ExceptionCheck(env)) { 503 return NULL; 504 } 505 len = (*env)->GetArrayLength(env, jcallerStack); 506 if (index < len) { 507 return (*env)->GetObjectArrayElement(env, jcallerStack, index); 508 } 509 return NULL; 510 } 511 512 /* 513 * Class: java_lang_ClassLoader_NativeLibrary 514 * Method: findBuiltinLib 515 * Signature: (Ljava/lang/String;)Ljava/lang/String; 516 */ 517 JNIEXPORT jstring JNICALL 518 Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib 519 (JNIEnv *env, jclass cls, jstring name) 520 { 521 const char *cname; 522 char *libName; 523 int prefixLen = (int) strlen(JNI_LIB_PREFIX); 524 int suffixLen = (int) strlen(JNI_LIB_SUFFIX); 525 int len; 526 jstring lib; 527 void *ret; 528 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 529 530 if (name == NULL) { 531 JNU_ThrowInternalError(env, "NULL filename for native library"); 532 return NULL; 533 } 534 // Can't call initIDs because it will recurse into NativeLibrary via 535 // FindClass to check context so set prochandle here as well. 536 procHandle = getProcessHandle(); 537 cname = JNU_GetStringPlatformChars(env, name, 0); 538 if (cname == NULL) { 539 return NULL; 540 } 541 // Copy name Skipping PREFIX 542 len = strlen(cname); 543 if (len <= (prefixLen+suffixLen)) { 544 JNU_ReleaseStringPlatformChars(env, name, cname); 545 return NULL; 546 } 547 libName = malloc(len + 1); //+1 for null if prefix+suffix == 0 548 if (libName == NULL) { 549 JNU_ThrowOutOfMemoryError(env, NULL); 550 return NULL; 551 } 552 if (len > prefixLen) { 553 strcpy(libName, cname+prefixLen); 554 } 555 JNU_ReleaseStringPlatformChars(env, name, cname); 556 557 // Strip SUFFIX 558 libName[strlen(libName)-suffixLen] = '\0'; 559 560 // Check for JNI_OnLoad_libname function 561 ret = findBuiltinJniFunction(env, procHandle, libName, JNI_TRUE); 562 if (ret != NULL) { 563 lib = JNU_NewStringPlatform(env, libName); 564 free(libName); 565 return lib; 566 } 567 free(libName); 568 return NULL; 569 }