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 36 /* defined in libverify.so/verify.dll (src file common/check_format.c) */ 37 extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed); 38 extern jboolean VerifyFixClassname(char *utf_name); 39 40 static JNINativeMethod methods[] = { 41 {"retrieveDirectives", "()Ljava/lang/AssertionStatusDirectives;", (void *)&JVM_AssertionStatusDirectives} 42 }; 43 44 JNIEXPORT void JNICALL 45 Java_java_lang_ClassLoader_registerNatives(JNIEnv *env, jclass cls) 46 { 47 (*env)->RegisterNatives(env, cls, methods, 48 sizeof(methods)/sizeof(JNINativeMethod)); 49 } 50 51 /* Convert java string to UTF char*. Use local buffer if possible, 52 otherwise malloc new memory. Returns null IFF malloc failed. */ 53 static char* 54 getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize) 55 { 56 char* utfStr = NULL; 57 58 int len = (*env)->GetStringUTFLength(env, str); 59 int unicode_len = (*env)->GetStringLength(env, str); 60 if (len >= bufSize) { 61 utfStr = malloc(len + 1); 62 if (utfStr == NULL) { 63 JNU_ThrowOutOfMemoryError(env, NULL); 64 return NULL; 65 } 66 } else { 67 utfStr = localBuf; 68 } 69 (*env)->GetStringUTFRegion(env, str, 0, unicode_len, utfStr); 70 71 return utfStr; 72 } 73 74 // The existence or signature of this method is not guaranteed since it 75 // supports a private method. This method will be changed in 1.7. 76 JNIEXPORT jclass JNICALL 77 Java_java_lang_ClassLoader_defineClass0(JNIEnv *env, 78 jobject loader, 79 jstring name, 80 jbyteArray data, 81 jint offset, 82 jint length, 83 jobject pd) 84 { 85 return Java_java_lang_ClassLoader_defineClass1(env, loader, name, data, offset, 86 length, pd, NULL); 87 } 88 89 JNIEXPORT jclass JNICALL 90 Java_java_lang_ClassLoader_defineClass1(JNIEnv *env, 91 jobject loader, 92 jstring name, 93 jbyteArray data, 94 jint offset, 95 jint length, 96 jobject pd, 97 jstring source) 98 { 99 jbyte *body; 100 char *utfName; 101 jclass result = 0; 102 char buf[128]; 103 char* utfSource; 104 char sourceBuf[1024]; 105 106 if (data == NULL) { 107 JNU_ThrowNullPointerException(env, 0); 108 return 0; 109 } 110 111 /* Work around 4153825. malloc crashes on Solaris when passed a 112 * negative size. 113 */ 114 if (length < 0) { 115 JNU_ThrowArrayIndexOutOfBoundsException(env, 0); 116 return 0; 117 } 118 119 body = (jbyte *)malloc(length); 120 121 if (body == 0) { 122 JNU_ThrowOutOfMemoryError(env, 0); 123 return 0; 124 } 125 126 (*env)->GetByteArrayRegion(env, data, offset, length, body); 127 128 if ((*env)->ExceptionOccurred(env)) 129 goto free_body; 130 131 if (name != NULL) { 132 utfName = getUTF(env, name, buf, sizeof(buf)); 133 if (utfName == NULL) { 134 JNU_ThrowOutOfMemoryError(env, 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 JNU_ThrowOutOfMemoryError(env, NULL); 146 goto free_utfName; 147 } 148 } else { 149 utfSource = NULL; 150 } 151 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); 152 153 if (utfSource && utfSource != sourceBuf) 154 free(utfSource); 155 156 free_utfName: 157 if (utfName && utfName != buf) 158 free(utfName); 159 160 free_body: 161 free(body); 162 return result; 163 } 164 165 JNIEXPORT jclass JNICALL 166 Java_java_lang_ClassLoader_defineClass2(JNIEnv *env, 167 jobject loader, 168 jstring name, 169 jobject data, 170 jint offset, 171 jint length, 172 jobject pd, 173 jstring source) 174 { 175 jbyte *body; 176 char *utfName; 177 jclass result = 0; 178 char buf[128]; 179 char* utfSource; 180 char sourceBuf[1024]; 181 182 assert(data != NULL); // caller fails if data is null. 183 assert(length >= 0); // caller passes ByteBuffer.remaining() for length, so never neg. 184 // caller passes ByteBuffer.position() for offset, and capacity() >= position() + remaining() 185 assert((*env)->GetDirectBufferCapacity(env, data) >= (offset + length)); 186 187 body = (*env)->GetDirectBufferAddress(env, data); 188 189 if (body == 0) { 190 JNU_ThrowNullPointerException(env, 0); 191 return 0; 192 } 193 194 body += offset; 195 196 if (name != NULL) { 197 utfName = getUTF(env, name, buf, sizeof(buf)); 198 if (utfName == NULL) { 199 JNU_ThrowOutOfMemoryError(env, NULL); 200 return result; 201 } 202 VerifyFixClassname(utfName); 203 } else { 204 utfName = NULL; 205 } 206 207 if (source != NULL) { 208 utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf)); 209 if (utfSource == NULL) { 210 JNU_ThrowOutOfMemoryError(env, NULL); 211 goto free_utfName; 212 } 213 } else { 214 utfSource = NULL; 215 } 216 result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource); 217 218 if (utfSource && utfSource != sourceBuf) 219 free(utfSource); 220 221 free_utfName: 222 if (utfName && utfName != buf) 223 free(utfName); 224 225 return result; 226 } 227 228 JNIEXPORT void JNICALL 229 Java_java_lang_ClassLoader_resolveClass0(JNIEnv *env, jobject this, 230 jclass cls) 231 { 232 if (cls == NULL) { 233 JNU_ThrowNullPointerException(env, 0); 234 return; 235 } 236 237 JVM_ResolveClass(env, cls); 238 } 239 240 /* 241 * Returns NULL if class not found. 242 */ 243 JNIEXPORT jclass JNICALL 244 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader, 245 jstring classname) 246 { 247 char *clname; 248 jclass cls = 0; 249 char buf[128]; 250 251 if (classname == NULL) { 252 return 0; 253 } 254 255 clname = getUTF(env, classname, buf, sizeof(buf)); 256 if (clname == NULL) { 257 JNU_ThrowOutOfMemoryError(env, NULL); 258 return NULL; 259 } 260 VerifyFixClassname(clname); 261 262 if (!VerifyClassname(clname, JNI_TRUE)) { /* expects slashed name */ 263 goto done; 264 } 265 266 cls = JVM_FindClassFromBootLoader(env, clname); 267 268 done: 269 if (clname != buf) { 270 free(clname); 271 } 272 273 return cls; 274 } 275 276 JNIEXPORT jclass JNICALL 277 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader, 278 jstring name) 279 { 280 if (name == NULL) { 281 return 0; 282 } else { 283 return JVM_FindLoadedClass(env, loader, name); 284 } 285 } 286 287 static jfieldID handleID; 288 static jfieldID jniVersionID; 289 290 static jboolean initIDs(JNIEnv *env) 291 { 292 if (handleID == 0) { 293 jclass this = 294 (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary"); 295 if (this == 0) 296 return JNI_FALSE; 297 handleID = (*env)->GetFieldID(env, this, "handle", "J"); 298 if (handleID == 0) 299 return JNI_FALSE; 300 jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I"); 301 if (jniVersionID == 0) 302 return JNI_FALSE; 303 } 304 return JNI_TRUE; 305 } 306 307 typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *); 308 typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *); 309 310 /* 311 * Class: java_lang_ClassLoader_NativeLibrary 312 * Method: load 313 * Signature: (Ljava/lang/String;)J 314 */ 315 JNIEXPORT void JNICALL 316 Java_java_lang_ClassLoader_00024NativeLibrary_load 317 (JNIEnv *env, jobject this, jstring name) 318 { 319 const char *cname; 320 jint jniVersion; 321 jthrowable cause; 322 void * handle; 323 324 if (!initIDs(env)) 325 return; 326 327 cname = JNU_GetStringPlatformChars(env, name, 0); 328 if (cname == 0) 329 return; 330 handle = JVM_LoadLibrary(cname); 331 if (handle) { 332 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS; 333 JNI_OnLoad_t JNI_OnLoad; 334 unsigned int i; 335 for (i = 0; i < sizeof(onLoadSymbols) / sizeof(char *); i++) { 336 JNI_OnLoad = (JNI_OnLoad_t) 337 JVM_FindLibraryEntry(handle, onLoadSymbols[i]); 338 if (JNI_OnLoad) { 339 break; 340 } 341 } 342 if (JNI_OnLoad) { 343 JavaVM *jvm; 344 (*env)->GetJavaVM(env, &jvm); 345 jniVersion = (*JNI_OnLoad)(jvm, NULL); 346 } else { 347 jniVersion = 0x00010001; 348 } 349 350 cause = (*env)->ExceptionOccurred(env); 351 if (cause) { 352 (*env)->ExceptionClear(env); 353 (*env)->Throw(env, cause); 354 JVM_UnloadLibrary(handle); 355 goto done; 356 } 357 358 if (!JVM_IsSupportedJNIVersion(jniVersion)) { 359 char msg[256]; 360 jio_snprintf(msg, sizeof(msg), 361 "unsupported JNI version 0x%08X required by %s", 362 jniVersion, cname); 363 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg); 364 JVM_UnloadLibrary(handle); 365 goto done; 366 } 367 (*env)->SetIntField(env, this, jniVersionID, jniVersion); 368 } else { 369 cause = (*env)->ExceptionOccurred(env); 370 if (cause) { 371 (*env)->ExceptionClear(env); 372 (*env)->SetLongField(env, this, handleID, (jlong)0); 373 (*env)->Throw(env, cause); 374 } 375 goto done; 376 } 377 (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle)); 378 379 done: 380 JNU_ReleaseStringPlatformChars(env, name, cname); 381 } 382 383 /* 384 * Class: java_lang_ClassLoader_NativeLibrary 385 * Method: unload 386 * Signature: ()V 387 */ 388 JNIEXPORT void JNICALL 389 Java_java_lang_ClassLoader_00024NativeLibrary_unload 390 (JNIEnv *env, jobject this) 391 { 392 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS; 393 void *handle; 394 JNI_OnUnload_t JNI_OnUnload; 395 unsigned int i; 396 397 if (!initIDs(env)) 398 return; 399 400 handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID)); 401 for (i = 0; i < sizeof(onUnloadSymbols) / sizeof(char *); i++) { 402 JNI_OnUnload = (JNI_OnUnload_t ) 403 JVM_FindLibraryEntry(handle, onUnloadSymbols[i]); 404 if (JNI_OnUnload) { 405 break; 406 } 407 } 408 409 if (JNI_OnUnload) { 410 JavaVM *jvm; 411 (*env)->GetJavaVM(env, &jvm); 412 (*JNI_OnUnload)(jvm, NULL); 413 } 414 JVM_UnloadLibrary(handle); 415 } 416 417 /* 418 * Class: java_lang_ClassLoader_NativeLibrary 419 * Method: find 420 * Signature: (Ljava/lang/String;J)J 421 */ 422 JNIEXPORT jlong JNICALL 423 Java_java_lang_ClassLoader_00024NativeLibrary_find 424 (JNIEnv *env, jobject this, jstring name) 425 { 426 jlong handle; 427 const char *cname; 428 jlong res; 429 430 if (!initIDs(env)) 431 return jlong_zero; 432 433 handle = (*env)->GetLongField(env, this, handleID); 434 cname = (*env)->GetStringUTFChars(env, name, 0); 435 if (cname == 0) 436 return jlong_zero; 437 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname)); 438 (*env)->ReleaseStringUTFChars(env, name, cname); 439 return res; 440 } 441 442 JNIEXPORT jobject JNICALL 443 Java_java_lang_ClassLoader_getCaller(JNIEnv *env, jclass cls, jint index) 444 { 445 jobjectArray jcallerStack; 446 int len; 447 448 jcallerStack = JVM_GetClassContext(env); 449 if ((*env)->ExceptionCheck(env)) { 450 return NULL; 451 } 452 len = (*env)->GetArrayLength(env, jcallerStack); 453 if (index < len) { 454 return (*env)->GetObjectArrayElement(env, jcallerStack, index); 455 } 456 return NULL; 457 } 458