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
Java_java_lang_ClassLoader_registerNatives(JNIEnv * env,jclass cls)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*
getUTF(JNIEnv * env,jstring str,char * localBuf,int bufSize)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
Java_java_lang_ClassLoader_defineClass1(JNIEnv * env,jclass cls,jobject loader,jstring name,jbyteArray data,jint offset,jint length,jobject pd,jstring source)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
Java_java_lang_ClassLoader_defineClass2(JNIEnv * env,jclass cls,jobject loader,jstring name,jobject data,jint offset,jint length,jobject pd,jstring source)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
Java_java_lang_ClassLoader_defineClass0(JNIEnv * env,jclass cls,jobject loader,jclass lookup,jstring name,jbyteArray data,jint offset,jint length,jobject pd,jboolean initialize,jint flags,jobject classData)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     result = 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
Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv * env,jobject loader,jstring classname)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
Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv * env,jobject loader,jstring name)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 }
316