1 /* 2 * Copyright (c) 1996, 2014, 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 /* 228 * Returns NULL if class not found. 229 */ 230 JNIEXPORT jclass JNICALL 231 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, 232 jstring classname) 233 { 234 char *clname; 235 jclass cls = 0; 236 char buf[128]; 237 238 if (classname == NULL) { 239 return 0; 240 } 241 242 clname = getUTF(env, classname, buf, sizeof(buf)); 243 if (clname == NULL) { 244 JNU_ThrowOutOfMemoryError(env, NULL); 245 return NULL; 246 } 247 VerifyFixClassname(clname); 248 249 if (!VerifyClassname(clname, JNI_TRUE)) { /* expects slashed name */ 250 goto done; 251 } 252 253 cls = JVM_FindClassFromBootLoader(env, clname); 254 255 done: 256 if (clname != buf) { 257 free(clname); 258 } 259 260 return cls; 261 } 262 263 JNIEXPORT jclass JNICALL 264 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader, 265 jstring name) 266 { 267 if (name == NULL) { 268 return 0; 269 } else { 270 return JVM_FindLoadedClass(env, loader, name); 271 } 272 } 273 274 static jfieldID handleID; 275 static jfieldID jniVersionID; 276 static jfieldID loadedID; 277 static void *procHandle; 278 279 static jboolean initIDs(JNIEnv *env) 280 { 281 if (handleID == 0) { 282 jclass this = 283 (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary"); 284 if (this == 0) 285 return JNI_FALSE; 286 handleID = (*env)->GetFieldID(env, this, "handle", "J"); 287 if (handleID == 0) 288 return JNI_FALSE; 289 jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I"); 290 if (jniVersionID == 0) 291 return JNI_FALSE; 292 loadedID = (*env)->GetFieldID(env, this, "loaded", "Z"); 293 if (loadedID == 0) 294 return JNI_FALSE; 295 procHandle = getProcessHandle(); 296 } 297 return JNI_TRUE; 298 } 299 300 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *); 301 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *); 302 303 /* 304 * Support for finding JNI_On(Un)Load_<lib_name> if it exists. 305 * If cname == NULL then just find normal JNI_On(Un)Load entry point 306 */ 307 static void *findJniFunction(JNIEnv *env, void *handle, 308 const char *cname, jboolean isLoad) { 309 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 310 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 311 const char **syms; 312 int symsLen; 313 void *entryName = NULL; 314 char *jniFunctionName; 315 int i; 316 size_t len; 317 318 // Check for JNI_On(Un)Load<_libname> function 319 if (isLoad) { 320 syms = onLoadSymbols; 321 symsLen = sizeof(onLoadSymbols) / sizeof(char *); 322 } else { 323 syms = onUnloadSymbols; 324 symsLen = sizeof(onUnloadSymbols) / sizeof(char *); 325 } 326 for (i = 0; i < symsLen; i++) { 327 // cname + sym + '_' + '\0' 328 if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) > 329 FILENAME_MAX) { 330 goto done; 331 } 332 jniFunctionName = malloc(len); 333 if (jniFunctionName == NULL) { 334 JNU_ThrowOutOfMemoryError(env, NULL); 335 goto done; 336 } 337 buildJniFunctionName(syms[i], cname, jniFunctionName); 338 entryName = JVM_FindLibraryEntry(handle, jniFunctionName); 339 free(jniFunctionName); 340 if(entryName) { 341 break; 342 } 343 } 344 345 done: 346 return entryName; 347 } 348 349 /* 350 * Class: java_lang_ClassLoader_NativeLibrary 351 * Method: load 352 * Signature: (Ljava/lang/String;Z)V 353 */ 354 JNIEXPORT void JNICALL 355 Java_java_lang_ClassLoader_00024NativeLibrary_load 356 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 357 { 358 const char *cname; 359 jint jniVersion; 360 jthrowable cause; 361 void * handle; 362 363 if (!initIDs(env)) 364 return; 365 366 cname = JNU_GetStringPlatformChars(env, name, 0); 367 if (cname == 0) 368 return; 369 handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname); 370 if (handle) { 371 JNI_OnLoad_t JNI_OnLoad; 372 JNI_OnLoad = (JNI_OnLoad_t)findJniFunction(env, handle, 373 isBuiltin ? cname : NULL, 374 JNI_TRUE); 375 if (JNI_OnLoad) { 376 JavaVM *jvm; 377 (*env)->GetJavaVM(env, &jvm); 378 jniVersion = (*JNI_OnLoad)(jvm, NULL); 379 } else { 380 jniVersion = 0x00010001; 381 } 382 383 cause = (*env)->ExceptionOccurred(env); 384 if (cause) { 385 (*env)->ExceptionClear(env); 386 (*env)->Throw(env, cause); 387 if (!isBuiltin) { 388 JVM_UnloadLibrary(handle); 389 } 390 goto done; 391 } 392 393 if (!JVM_IsSupportedJNIVersion(jniVersion) || 394 (isBuiltin && jniVersion < JNI_VERSION_1_8)) { 395 char msg[256]; 396 jio_snprintf(msg, sizeof(msg), 397 "unsupported JNI version 0x%08X required by %s", 398 jniVersion, cname); 399 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); 400 if (!isBuiltin) { 401 JVM_UnloadLibrary(handle); 402 } 403 goto done; 404 } 405 (*env)->SetIntField(env, this, jniVersionID, jniVersion); 406 } else { 407 cause = (*env)->ExceptionOccurred(env); 408 if (cause) { 409 (*env)->ExceptionClear(env); 410 (*env)->SetLongField(env, this, handleID, (jlong)0); 411 (*env)->Throw(env, cause); 412 } 413 goto done; 414 } 415 (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); 416 (*env)->SetBooleanField(env, this, loadedID, JNI_TRUE); 417 418 done: 419 JNU_ReleaseStringPlatformChars(env, name, cname); 420 } 421 422 /* 423 * Class: java_lang_ClassLoader_NativeLibrary 424 * Method: unload 425 * Signature: (Z)V 426 */ 427 JNIEXPORT void JNICALL 428 Java_java_lang_ClassLoader_00024NativeLibrary_unload 429 (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin) 430 { 431 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 432 void *handle; 433 JNI_OnUnload_t JNI_OnUnload; 434 const char *cname; 435 436 if (!initIDs(env)) 437 return; 438 cname = JNU_GetStringPlatformChars(env, name, 0); 439 if (cname == NULL) { 440 return; 441 } 442 handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID)); 443 JNI_OnUnload = (JNI_OnUnload_t )findJniFunction(env, handle, 444 isBuiltin ? cname : NULL, 445 JNI_FALSE); 446 if (JNI_OnUnload) { 447 JavaVM *jvm; 448 (*env)->GetJavaVM(env, &jvm); 449 (*JNI_OnUnload)(jvm, NULL); 450 } 451 if (!isBuiltin) { 452 JVM_UnloadLibrary(handle); 453 } 454 JNU_ReleaseStringPlatformChars(env, name, cname); 455 } 456 457 /* 458 * Class: java_lang_ClassLoader_NativeLibrary 459 * Method: find 460 * Signature: (Ljava/lang/String;)J 461 */ 462 JNIEXPORT jlong JNICALL 463 Java_java_lang_ClassLoader_00024NativeLibrary_find 464 (JNIEnv *env, jobject this, jstring name) 465 { 466 jlong handle; 467 const char *cname; 468 jlong res; 469 470 if (!initIDs(env)) 471 return jlong_zero; 472 473 handle = (*env)->GetLongField(env, this, handleID); 474 cname = (*env)->GetStringUTFChars(env, name, 0); 475 if (cname == 0) 476 return jlong_zero; 477 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname)); 478 (*env)->ReleaseStringUTFChars(env, name, cname); 479 return res; 480 } 481 /* 482 * Class: java_lang_ClassLoader_NativeLibrary 483 * Method: findBuiltinLib 484 * Signature: (Ljava/lang/String;)Ljava/lang/String; 485 */ 486 JNIEXPORT jstring JNICALL 487 Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib 488 (JNIEnv *env, jclass cls, jstring name) 489 { 490 const char *cname; 491 char *libName; 492 size_t prefixLen = strlen(JNI_LIB_PREFIX); 493 size_t suffixLen = strlen(JNI_LIB_SUFFIX); 494 size_t len; 495 jstring lib; 496 void *ret; 497 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 498 499 if (name == NULL) { 500 JNU_ThrowInternalError(env, "NULL filename for native library"); 501 return NULL; 502 } 503 // Can't call initIDs because it will recurse into NativeLibrary via 504 // FindClass to check context so set prochandle here as well. 505 procHandle = getProcessHandle(); 506 cname = JNU_GetStringPlatformChars(env, name, 0); 507 if (cname == NULL) { 508 return NULL; 509 } 510 // Copy name Skipping PREFIX 511 len = strlen(cname); 512 if (len <= (prefixLen+suffixLen)) { 513 JNU_ReleaseStringPlatformChars(env, name, cname); 514 return NULL; 515 } 516 libName = malloc(len + 1); //+1 for null if prefix+suffix == 0 517 if (libName == NULL) { 518 JNU_ReleaseStringPlatformChars(env, name, cname); 519 JNU_ThrowOutOfMemoryError(env, NULL); 520 return NULL; 521 } 522 if (len > prefixLen) { 523 strcpy(libName, cname+prefixLen); 524 } 525 JNU_ReleaseStringPlatformChars(env, name, cname); 526 527 // Strip SUFFIX 528 libName[strlen(libName)-suffixLen] = '\0'; 529 530 // Check for JNI_OnLoad_libname function 531 ret = findJniFunction(env, procHandle, libName, JNI_TRUE); 532 if (ret != NULL) { 533 lib = JNU_NewStringPlatform(env, libName); 534 free(libName); 535 return lib; 536 } 537 free(libName); 538 return NULL; 539 }