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