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