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