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