1 /*
   2  * Copyright (c) 1996, 2020, 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 <string.h>
  36 
  37 static JNINativeMethod methods[] = {
  38     {"retrieveDirectives",  "()Ljava/lang/AssertionStatusDirectives;", (void *)&JVM_AssertionStatusDirectives}
  39 };
  40 
  41 JNIEXPORT void JNICALL
  42 Java_java_lang_ClassLoader_registerNatives(JNIEnv *env, jclass cls)
  43 {
  44     (*env)->RegisterNatives(env, cls, methods,
  45                             sizeof(methods)/sizeof(JNINativeMethod));
  46 }
  47 
  48 /* Convert java string to UTF char*. Use local buffer if possible,
  49    otherwise malloc new memory. Returns null IFF malloc failed. */
  50 static char*
  51 getUTF(JNIEnv *env, jstring str, char* localBuf, int bufSize)
  52 {
  53     char* utfStr = NULL;
  54 
  55     int len = (*env)->GetStringUTFLength(env, str);
  56     int unicode_len = (*env)->GetStringLength(env, str);
  57     if (len >= bufSize) {
  58         utfStr = malloc(len + 1);
  59         if (utfStr == NULL) {
  60             JNU_ThrowOutOfMemoryError(env, NULL);
  61             return NULL;
  62         }
  63     } else {
  64         utfStr = localBuf;
  65     }
  66     (*env)->GetStringUTFRegion(env, str, 0, unicode_len, utfStr);
  67 
  68     return utfStr;
  69 }
  70 
  71 JNIEXPORT jclass JNICALL
  72 Java_java_lang_ClassLoader_defineClass1(JNIEnv *env,
  73                                         jclass cls,
  74                                         jobject loader,
  75                                         jstring name,
  76                                         jbyteArray data,
  77                                         jint offset,
  78                                         jint length,
  79                                         jobject pd,
  80                                         jstring source)
  81 {
  82     jbyte *body;
  83     char *utfName;
  84     jclass result = 0;
  85     char buf[128];
  86     char* utfSource;
  87     char sourceBuf[1024];
  88 
  89     if (data == NULL) {
  90         JNU_ThrowNullPointerException(env, 0);
  91         return 0;
  92     }
  93 
  94     /* Work around 4153825. malloc crashes on Solaris when passed a
  95      * negative size.
  96      */
  97     if (length < 0) {
  98         JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
  99         return 0;
 100     }
 101 
 102     body = (jbyte *)malloc(length);
 103 
 104     if (body == 0) {
 105         JNU_ThrowOutOfMemoryError(env, 0);
 106         return 0;
 107     }
 108 
 109     (*env)->GetByteArrayRegion(env, data, offset, length, body);
 110 
 111     if ((*env)->ExceptionOccurred(env))
 112         goto free_body;
 113 
 114     if (name != NULL) {
 115         utfName = getUTF(env, name, buf, sizeof(buf));
 116         if (utfName == NULL) {
 117             goto free_body;
 118         }
 119         fixClassname(utfName);
 120     } else {
 121         utfName = NULL;
 122     }
 123 
 124     if (source != NULL) {
 125         utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf));
 126         if (utfSource == NULL) {
 127             goto free_utfName;
 128         }
 129     } else {
 130         utfSource = NULL;
 131     }
 132     result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource);
 133 
 134     if (utfSource && utfSource != sourceBuf)
 135         free(utfSource);
 136 
 137  free_utfName:
 138     if (utfName && utfName != buf)
 139         free(utfName);
 140 
 141  free_body:
 142     free(body);
 143     return result;
 144 }
 145 
 146 JNIEXPORT jclass JNICALL
 147 Java_java_lang_ClassLoader_defineClass2(JNIEnv *env,
 148                                         jclass cls,
 149                                         jobject loader,
 150                                         jstring name,
 151                                         jobject data,
 152                                         jint offset,
 153                                         jint length,
 154                                         jobject pd,
 155                                         jstring source)
 156 {
 157     jbyte *body;
 158     char *utfName;
 159     jclass result = 0;
 160     char buf[128];
 161     char* utfSource;
 162     char sourceBuf[1024];
 163 
 164     assert(data != NULL); // caller fails if data is null.
 165     assert(length >= 0);  // caller passes ByteBuffer.remaining() for length, so never neg.
 166     // caller passes ByteBuffer.position() for offset, and capacity() >= position() + remaining()
 167     assert((*env)->GetDirectBufferCapacity(env, data) >= (offset + length));
 168 
 169     body = (*env)->GetDirectBufferAddress(env, data);
 170 
 171     if (body == 0) {
 172         JNU_ThrowNullPointerException(env, 0);
 173         return 0;
 174     }
 175 
 176     body += offset;
 177 
 178     if (name != NULL) {
 179         utfName = getUTF(env, name, buf, sizeof(buf));
 180         if (utfName == NULL) {
 181             JNU_ThrowOutOfMemoryError(env, NULL);
 182             return result;
 183         }
 184         fixClassname(utfName);
 185     } else {
 186         utfName = NULL;
 187     }
 188 
 189     if (source != NULL) {
 190         utfSource = getUTF(env, source, sourceBuf, sizeof(sourceBuf));
 191         if (utfSource == NULL) {
 192             JNU_ThrowOutOfMemoryError(env, NULL);
 193             goto free_utfName;
 194         }
 195     } else {
 196         utfSource = NULL;
 197     }
 198     result = JVM_DefineClassWithSource(env, utfName, loader, body, length, pd, utfSource);
 199 
 200     if (utfSource && utfSource != sourceBuf)
 201         free(utfSource);
 202 
 203  free_utfName:
 204     if (utfName && utfName != buf)
 205         free(utfName);
 206 
 207     return result;
 208 }
 209 
 210 JNIEXPORT jclass JNICALL
 211 Java_java_lang_ClassLoader_defineClass0(JNIEnv *env,
 212                                         jclass cls,
 213                                         jobject loader,
 214                                         jclass lookup,
 215                                         jstring name,
 216                                         jbyteArray data,
 217                                         jint offset,
 218                                         jint length,
 219                                         jobject pd,
 220                                         jboolean initialize,
 221                                         jint flags,
 222                                         jobject classData)
 223 {
 224     jbyte *body;
 225     char *utfName;
 226     jclass result = 0;
 227     char buf[128];
 228 
 229     if (data == NULL) {
 230         JNU_ThrowNullPointerException(env, 0);
 231         return 0;
 232     }
 233 
 234     /* Work around 4153825. malloc crashes on Solaris when passed a
 235      * negative size.
 236      */
 237     if (length < 0) {
 238         JNU_ThrowArrayIndexOutOfBoundsException(env, 0);
 239         return 0;
 240     }
 241 
 242     body = (jbyte *)malloc(length);
 243     if (body == 0) {
 244         JNU_ThrowOutOfMemoryError(env, 0);
 245         return 0;
 246     }
 247 
 248     (*env)->GetByteArrayRegion(env, data, offset, length, body);
 249 
 250     if ((*env)->ExceptionOccurred(env))
 251         goto free_body;
 252 
 253     if (name != NULL) {
 254         utfName = getUTF(env, name, buf, sizeof(buf));
 255         if (utfName == NULL) {
 256             goto free_body;
 257         }
 258         fixClassname(utfName);
 259     } else {
 260         utfName = NULL;
 261     }
 262 
 263     return JVM_LookupDefineClass(env, lookup, utfName, body, length, pd, initialize, flags, classData);
 264 
 265  free_body:
 266     free(body);
 267     return result;
 268 }
 269 
 270 /*
 271  * Returns NULL if class not found.
 272  */
 273 JNIEXPORT jclass JNICALL
 274 Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
 275                                               jstring classname)
 276 {
 277     char *clname;
 278     jclass cls = 0;
 279     char buf[128];
 280 
 281     if (classname == NULL) {
 282         return 0;
 283     }
 284 
 285     clname = getUTF(env, classname, buf, sizeof(buf));
 286     if (clname == NULL) {
 287         JNU_ThrowOutOfMemoryError(env, NULL);
 288         return NULL;
 289     }
 290     fixClassname(clname);
 291 
 292     if (!verifyClassname(clname, JNI_TRUE)) {  /* expects slashed name */
 293         goto done;
 294     }
 295 
 296     cls = JVM_FindClassFromBootLoader(env, clname);
 297 
 298  done:
 299     if (clname != buf) {
 300         free(clname);
 301     }
 302 
 303     return cls;
 304 }
 305 
 306 JNIEXPORT jclass JNICALL
 307 Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader,
 308                                            jstring name)
 309 {
 310     if (name == NULL) {
 311         return 0;
 312     } else {
 313         return JVM_FindLoadedClass(env, loader, name);
 314     }
 315 }