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