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 goto free_body; 136 } 137 VerifyFixClassname(utfName); 138 } else { 139 utfName = NULL; 140 } 141 142 if (source != NULL) { 143 utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf)); 144 if (utfSource == NULL) { 145 goto free_utfName; 146 } 147 } else { 148 utfSource = NULL; 149 } 150 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); 151 152 if (utfSource && utfSource != sourceBuf) 153 free(utfSource); 154 155 free_utfName: 156 if (utfName && utfName != buf) 157 free(utfName); 158 159 free_body: 160 free(body); 161 return result; 162 } 163 164 JNIEXPORT jclass JNICALL 165 Java_java_lang_ClassLoader_defineClass2(JNIEnv *env, 166 jobject loader, 167 jstring name, 168 jobject data, 169 jint offset, 170 jint length, 171 jobject pd, 172 jstring source) 173 { 174 jbyte *body; 175 char *utfName; 176 jclass result = 0; 177 char buf[128]; 178 char* utfSource; 179 char sourceBuf[1024]; 180 181 assert(data != NULL); // caller fails if data is null. 182 assert(length >= 0); // caller passes ByteBuffer.remaining() for length, so never neg. 183 // caller passes ByteBuffer.position() for offset, and capacity() >= position() + remaining() 184 assert((*env)->GetDirectBufferCapacity(env, data) >= (offset + length)); 185 186 body = (*env)->GetDirectBufferAddress(env, data); 187 188 if (body == 0) { 189 JNU_ThrowNullPointerException(env, 0); 190 return 0; 191 } 192 193 body += offset; 194 195 if (name != NULL) { 196 utfName = getUTF(env, name, buf, sizeof(buf)); 197 if (utfName == NULL) { 198 JNU_ThrowOutOfMemoryError(env, NULL); 199 return result; 200 } 201 VerifyFixClassname(utfName); 202 } else { 203 utfName = NULL; 204 } 205 206 if (source != NULL) { 207 utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf)); 208 if (utfSource == NULL) { 209 JNU_ThrowOutOfMemoryError(env, NULL); 210 goto free_utfName; 211 } 212 } else { 213 utfSource = NULL; 214 } 215 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); 216 217 if (utfSource && utfSource != sourceBuf) 218 free(utfSource); 219 220 free_utfName: 221 if (utfName && utfName != buf) 222 free(utfName); 223 224 return result; 225 } 226 227 JNIEXPORT void JNICALL 228 Java_java_lang_ClassLoader_resolveClass0(JNIEnv *env, jobject this, 229 jclass cls) 230 { 231 if (cls == NULL) { 232 JNU_ThrowNullPointerException(env, 0); 233 return; 234 } 235 236 JVM_ResolveClass(env, cls); 237 } 238 239 /* 240 * Returns NULL if class not found. 241 */ 242 JNIEXPORT jclass JNICALL 243 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, 244 jstring classname) 245 { 246 char *clname; 247 jclass cls = 0; 248 char buf[128]; 249 250 if (classname == NULL) { 251 return 0; 252 } 253 254 clname = getUTF(env, classname, buf, sizeof(buf)); 255 if (clname == NULL) { 256 JNU_ThrowOutOfMemoryError(env, NULL); 257 return NULL; 258 } 259 VerifyFixClassname(clname); 260 261 if (!VerifyClassname(clname, JNI_TRUE)) { /* expects slashed name */ 262 goto done; 263 } 264 265 cls = JVM_FindClassFromBootLoader(env, clname); 266 267 done: 268 if (clname != buf) { 269 free(clname); 270 } 271 272 return cls; 273 } 274 275 JNIEXPORT jclass JNICALL 276 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader, 277 jstring name) 278 { 279 if (name == NULL) { 280 return 0; 281 } else { 282 return JVM_FindLoadedClass(env, loader, name); 283 } 284 } 285 286 static jfieldID handleID; 287 static jfieldID jniVersionID; 288 static jfieldID loadedID; 289 static void *procHandle; 290 291 static jboolean initIDs(JNIEnv *env) 292 { 293 if (handleID == 0) { 294 jclass this = 295 (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary"); 296 if (this == 0) 297 return JNI_FALSE; 298 handleID = (*env)->GetFieldID(env, this, "handle", "J"); 299 if (handleID == 0) 300 return JNI_FALSE; 301 jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I"); 302 if (jniVersionID == 0) 303 return JNI_FALSE; 304 loadedID = (*env)->GetFieldID(env, this, "loaded", "Z"); 305 if (loadedID == 0) 306 return JNI_FALSE; 307 procHandle = getProcessHandle(); 308 } 309 return JNI_TRUE; 310 } 311 312 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *); 313 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *); 314 315 /* 316 * Support for finding JNI_On(Un)Load_<lib_name> if it exists. 317 * If cname == NULL then just find normal JNI_On(Un)Load entry point 318 */ 319 static void *findJniFunction(JNIEnv *env, void *handle, 320 const char *cname, jboolean isLoad) { 321 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 322 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 323 const char **syms; 324 int symsLen; 325 void *entryName = NULL; 326 char *jniFunctionName; 327 int i; 328 int len; 329 330 // Check for JNI_On(Un)Load<_libname> function 331 if (isLoad) { 332 syms = onLoadSymbols; 333 symsLen = sizeof(onLoadSymbols) / sizeof(char *); 334 } else { 335 syms = onUnloadSymbols; 336 symsLen = sizeof(onUnloadSymbols) / sizeof(char *); 337 } 338 for (i = 0; i < symsLen; i++) { 339 // cname + sym + '_' + '\0' 340 if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) > 341 FILENAME_MAX) { 342 goto done; 343 } 344 jniFunctionName = malloc(len); 345 if (jniFunctionName == NULL) { 346 JNU_ThrowOutOfMemoryError(env, NULL); 347 goto done; 348 } 349 buildJniFunctionName(syms[i], cname, jniFunctionName); 350 entryName = JVM_FindLibraryEntry(handle, jniFunctionName); 351 free(jniFunctionName); 352 if(entryName) { 353 break; 354 } 355 } 356 357 done: 358 return entryName; 359 } 360 361 /* 362 * Class: java_lang_ClassLoader_NativeLibrary 363 * Method: load 364 * Signature: (Ljava/lang/String;Z)V 365 */ 366 JNIEXPORT void JNICALL 367 Java_java_lang_ClassLoader_00024NativeLibrary_load 368 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 369 { 370 const char *cname; 371 jint jniVersion; 372 jthrowable cause; 373 void * handle; 374 375 if (!initIDs(env)) 376 return; 377 378 cname = JNU_GetStringPlatformChars(env, name, 0); 379 if (cname == 0) 380 return; 381 handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); 382 if (handle) { 383 JNI_OnLoad_t JNI_OnLoad; 384 JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle, 385 isBuiltin ? cname : NULL, 386 JNI_TRUE); 387 if (JNI_OnLoad) { 388 JavaVM *jvm; 389 (*env)->GetJavaVM(env, &jvm); 390 jniVersion = (*JNI_OnLoad)(jvm, NULL); 391 } else { 392 jniVersion = 0x00010001; 393 } 394 395 cause = (*env)->ExceptionOccurred(env); 396 if (cause) { 397 (*env)->ExceptionClear(env); 398 (*env)->Throw(env, cause); 399 if (!isBuiltin) { 400 JVM_UnloadLibrary(handle); 401 } 402 goto done; 403 } 404 405 if (!JVM_IsSupportedJNIVersion(jniVersion) || 406 (isBuiltin && jniVersion < JNI_VERSION_1_8)) { 407 char msg[256]; 408 jio_snprintf(msg, sizeof(msg), 409 "unsupported JNI version 0x%08X required by %s", 410 jniVersion, cname); 411 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); 412 if (!isBuiltin) { 413 JVM_UnloadLibrary(handle); 414 } 415 goto done; 416 } 417 (*env)->SetIntField(env, this, jniVersionID, jniVersion); 418 } else { 419 cause = (*env)->ExceptionOccurred(env); 420 if (cause) { 421 (*env)->ExceptionClear(env); 422 (*env)->SetLongField(env, this, handleID, (jlong)0); 423 (*env)->Throw(env, cause); 424 } 425 goto done; 426 } 427 (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); 428 (*env)->SetBooleanField(env, this, loadedID, JNI_TRUE); 429 430 done: 431 JNU_ReleaseStringPlatformChars(env, name, cname); 432 } 433 434 /* 435 * Class: java_lang_ClassLoader_NativeLibrary 436 * Method: unload 437 * Signature: (Z)V 438 */ 439 JNIEXPORT void JNICALL 440 Java_java_lang_ClassLoader_00024NativeLibrary_unload 441 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 442 { 443 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 444 void *handle; 445 JNI_OnUnload_t JNI_OnUnload; 446 const char *cname; 447 448 if (!initIDs(env)) 449 return; 450 cname = JNU_GetStringPlatformChars(env, name, 0); 451 if (cname == NULL) { 452 return; 453 } 454 handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID)); 455 JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle, 456 isBuiltin ? cname : NULL, 457 JNI_FALSE); 458 if (JNI_OnUnload) { 459 JavaVM *jvm; 460 (*env)->GetJavaVM(env, &jvm); 461 (*JNI_OnUnload)(jvm, NULL); 462 } 463 if (!isBuiltin) { 464 JVM_UnloadLibrary(handle); 465 } 466 JNU_ReleaseStringPlatformChars(env, name, cname); 467 } 468 469 /* 470 * Class: java_lang_ClassLoader_NativeLibrary 471 * Method: find 472 * Signature: (Ljava/lang/String;)J 473 */ 474 JNIEXPORT jlong JNICALL 475 Java_java_lang_ClassLoader_00024NativeLibrary_find 476 (JNIEnv *env, jobject this, jstring name) 477 { 478 jlong handle; 479 const char *cname; 480 jlong res; 481 482 if (!initIDs(env)) 483 return jlong_zero; 484 485 handle = (*env)->GetLongField(env, this, handleID); 486 cname = (*env)->GetStringUTFChars(env, name, 0); 487 if (cname == 0) 488 return jlong_zero; 489 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname)); 490 (*env)->ReleaseStringUTFChars(env, name, cname); 491 return res; 492 } 493 /* 494 * Class: java_lang_ClassLoader_NativeLibrary 495 * Method: findBuiltinLib 496 * Signature: (Ljava/lang/String;)Ljava/lang/String; 497 */ 498 JNIEXPORT jstring JNICALL 499 Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib 500 (JNIEnv *env, jclass cls, jstring name) 501 { 502 const char *cname; 503 char *libName; 504 int prefixLen = (int) strlen(JNI_LIB_PREFIX); 505 int suffixLen = (int) strlen(JNI_LIB_SUFFIX); 506 int len; 507 jstring lib; 508 void *ret; 509 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 510 511 if (name == NULL) { 512 JNU_ThrowInternalError(env, "NULL filename for native library"); 513 return NULL; 514 } 515 // Can't call initIDs because it will recurse into NativeLibrary via 516 // FindClass to check context so set prochandle here as well. 517 procHandle = getProcessHandle(); 518 cname = JNU_GetStringPlatformChars(env, name, 0); 519 if (cname == NULL) { 520 return NULL; 521 } 522 // Copy name Skipping PREFIX 523 len = strlen(cname); 524 if (len <= (prefixLen+suffixLen)) { 525 JNU_ReleaseStringPlatformChars(env, name, cname); 526 return NULL; 527 } 528 libName = malloc(len + 1); //+1 for null if prefix+suffix == 0 529 if (libName == NULL) { 530 JNU_ReleaseStringPlatformChars(env, name, cname); 531 JNU_ThrowOutOfMemoryError(env, NULL); 532 return NULL; 533 } 534 if (len > prefixLen) { 535 strcpy(libName, cname+prefixLen); 536 } 537 JNU_ReleaseStringPlatformChars(env, name, cname); 538 539 // Strip SUFFIX 540 libName[strlen(libName)-suffixLen] = '\0'; 541 542 // Check for JNI_OnLoad_libname function 543 ret = findJniFunction(env, procHandle, libName, JNI_TRUE); 544 if (ret != NULL) { 545 lib = JNU_NewStringPlatform(env, libName); 546 free(libName); 547 return lib; 548 } 549 free(libName); 550 return NULL; 551 }