blob: 6f5960af5bf54fe8c1651e252df603193a3eaffe [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1996-2005 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any 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) */
37extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
38extern jboolean VerifyFixClassname(char *utf_name);
39
40static JNINativeMethod methods[] = {
41 {"retrieveDirectives", "()Ljava/lang/AssertionStatusDirectives;", (void *)&JVM_AssertionStatusDirectives}
42};
43
44JNIEXPORT void JNICALL
45Java_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. */
53static char*
54getUTF(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.
76JNIEXPORT jclass JNICALL
77Java_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
89JNIEXPORT jclass JNICALL
90Java_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
165JNIEXPORT jclass JNICALL
166Java_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
228JNIEXPORT void JNICALL
229Java_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
240JNIEXPORT jclass JNICALL
241Java_java_lang_ClassLoader_findBootstrapClass(JNIEnv *env, jobject loader,
242 jstring classname)
243{
244 char *clname;
245 jclass cls = 0;
246 char buf[128];
247
248 if (classname == NULL) {
249 JNU_ThrowClassNotFoundException(env, 0);
250 return 0;
251 }
252
253 clname = getUTF(env, classname, buf, sizeof(buf));
254 if (clname == NULL) {
255 JNU_ThrowOutOfMemoryError(env, NULL);
256 return NULL;
257 }
258 VerifyFixClassname(clname);
259
260 if (!VerifyClassname(clname, JNI_TRUE)) { /* expects slashed name */
261 JNU_ThrowClassNotFoundException(env, clname);
262 goto done;
263 }
264
265 cls = JVM_FindClassFromClassLoader(env, clname, JNI_FALSE, 0, JNI_FALSE);
266
267 done:
268 if (clname != buf) {
269 free(clname);
270 }
271
272 return cls;
273}
274
275JNIEXPORT jclass JNICALL
276Java_java_lang_ClassLoader_findLoadedClass0(JNIEnv *env, jobject loader,
277 jstring name)
278{
279 if (name == NULL) {
280 return 0;
281 } else {
282 return JVM_FindLoadedClass(env, loader, name);
283 }
284}
285
286static jfieldID handleID;
287static jfieldID jniVersionID;
288
289static jboolean initIDs(JNIEnv *env)
290{
291 if (handleID == 0) {
292 jclass this =
293 (*env)->FindClass(env, "java/lang/ClassLoader$NativeLibrary");
294 if (this == 0)
295 return JNI_FALSE;
296 handleID = (*env)->GetFieldID(env, this, "handle", "J");
297 if (handleID == 0)
298 return JNI_FALSE;
299 jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I");
300 if (jniVersionID == 0)
301 return JNI_FALSE;
302 }
303 return JNI_TRUE;
304}
305
306typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *);
307typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *);
308
309/*
310 * Class: java_lang_ClassLoader_NativeLibrary
311 * Method: load
312 * Signature: (Ljava/lang/String;)J
313 */
314JNIEXPORT void JNICALL
315Java_java_lang_ClassLoader_00024NativeLibrary_load
316 (JNIEnv *env, jobject this, jstring name)
317{
318 const char *cname;
319 jint jniVersion;
320 jthrowable cause;
321 void * handle;
322
323 if (!initIDs(env))
324 return;
325
326 cname = JNU_GetStringPlatformChars(env, name, 0);
327 if (cname == 0)
328 return;
329 handle = JVM_LoadLibrary(cname);
330 if (handle) {
331 const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
332 JNI_OnLoad_t JNI_OnLoad;
333 int i;
334 for (i = 0; i < sizeof(onLoadSymbols) / sizeof(char *); i++) {
335 JNI_OnLoad = (JNI_OnLoad_t)
336 JVM_FindLibraryEntry(handle, onLoadSymbols[i]);
337 if (JNI_OnLoad) {
338 break;
339 }
340 }
341 if (JNI_OnLoad) {
342 JavaVM *jvm;
343 (*env)->GetJavaVM(env, &jvm);
344 jniVersion = (*JNI_OnLoad)(jvm, NULL);
345 } else {
346 jniVersion = 0x00010001;
347 }
348
349 cause = (*env)->ExceptionOccurred(env);
350 if (cause) {
351 (*env)->ExceptionClear(env);
352 (*env)->Throw(env, cause);
353 JVM_UnloadLibrary(handle);
354 goto done;
355 }
356
357 if (!JVM_IsSupportedJNIVersion(jniVersion)) {
358 char msg[256];
359 jio_snprintf(msg, sizeof(msg),
360 "unsupported JNI version 0x%08X required by %s",
361 jniVersion, cname);
362 JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);
363 JVM_UnloadLibrary(handle);
364 goto done;
365 }
366 (*env)->SetIntField(env, this, jniVersionID, jniVersion);
367 } else {
368 cause = (*env)->ExceptionOccurred(env);
369 if (cause) {
370 (*env)->ExceptionClear(env);
371 (*env)->SetLongField(env, this, handleID, (jlong)NULL);
372 (*env)->Throw(env, cause);
373 }
374 goto done;
375 }
376 (*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle));
377
378 done:
379 JNU_ReleaseStringPlatformChars(env, name, cname);
380}
381
382/*
383 * Class: java_lang_ClassLoader_NativeLibrary
384 * Method: unload
385 * Signature: ()V
386 */
387JNIEXPORT void JNICALL
388Java_java_lang_ClassLoader_00024NativeLibrary_unload
389 (JNIEnv *env, jobject this)
390{
391 const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
392 void *handle;
393 JNI_OnUnload_t JNI_OnUnload;
394 int i;
395
396 if (!initIDs(env))
397 return;
398
399 handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID));
400 for (i = 0; i < sizeof(onUnloadSymbols) / sizeof(char *); i++) {
401 JNI_OnUnload = (JNI_OnUnload_t )
402 JVM_FindLibraryEntry(handle, onUnloadSymbols[i]);
403 if (JNI_OnUnload) {
404 break;
405 }
406 }
407
408 if (JNI_OnUnload) {
409 JavaVM *jvm;
410 (*env)->GetJavaVM(env, &jvm);
411 (*JNI_OnUnload)(jvm, NULL);
412 }
413 JVM_UnloadLibrary(handle);
414}
415
416/*
417 * Class: java_lang_ClassLoader_NativeLibrary
418 * Method: find
419 * Signature: (Ljava/lang/String;J)J
420 */
421JNIEXPORT jlong JNICALL
422Java_java_lang_ClassLoader_00024NativeLibrary_find
423 (JNIEnv *env, jobject this, jstring name)
424{
425 jlong handle;
426 const char *cname;
427 jlong res;
428
429 if (!initIDs(env))
430 return jlong_zero;
431
432 handle = (*env)->GetLongField(env, this, handleID);
433 cname = (*env)->GetStringUTFChars(env, name, 0);
434 if (cname == 0)
435 return jlong_zero;
436 res = ptr_to_jlong(JVM_FindLibraryEntry(jlong_to_ptr(handle), cname));
437 (*env)->ReleaseStringUTFChars(env, name, cname);
438 return res;
439}