src/share/native/java/lang/ClassLoader.c
Print this page
@@ -30,10 +30,11 @@
#include "jni_util.h"
#include "jlong.h"
#include "jvm.h"
#include "java_lang_ClassLoader.h"
#include "java_lang_ClassLoader_NativeLibrary.h"
+#include <string.h>
/* defined in libverify.so/verify.dll (src file common/check_format.c) */
extern jboolean VerifyClassname(char *utf_name, jboolean arrayAllowed);
extern jboolean VerifyFixClassname(char *utf_name);
@@ -284,10 +285,12 @@
}
}
static jfieldID handleID;
static jfieldID jniVersionID;
+static jfieldID loadedID;
+static void *procHandle;
static jboolean initIDs(JNIEnv *env)
{
if (handleID == 0) {
jclass this =
@@ -298,25 +301,79 @@
if (handleID == 0)
return JNI_FALSE;
jniVersionID = (*env)->GetFieldID(env, this, "jniVersion", "I");
if (jniVersionID == 0)
return JNI_FALSE;
+ loadedID = (*env)->GetFieldID(env, this, "loaded", "Z");
+ if (loadedID == 0)
+ return JNI_FALSE;
+ procHandle = getProcessHandle();
}
return JNI_TRUE;
}
typedef jint (JNICALL *JNI_OnLoad_t)(JavaVM *, void *);
typedef void (JNICALL *JNI_OnUnload_t)(JavaVM *, void *);
/*
+ * Support for builtin library. JNI_On(Un)Load_<lib_name> if it exists.
+ * If cname == NULL then just find normal JNI_On(Un)Load entry point
+ */
+static void *findBuiltinJniFunction(JNIEnv *env, void *handle,
+ const char *cname, jboolean isLoad) {
+ const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
+ const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
+ const char **syms;
+ int symsLen;
+ void *entryName = NULL;
+ char *jniEntryName;
+ int i;
+ int len;
+
+ // Check for JNI_On(Un)Load<_libname> function
+ if (isLoad) {
+ syms = onLoadSymbols;
+ symsLen = sizeof(onLoadSymbols) / sizeof(char *);
+ } else {
+ syms = onUnloadSymbols;
+ symsLen = sizeof(onUnloadSymbols) / sizeof(char *);
+ }
+ for (i = 0; i < symsLen; i++) {
+ // cname + sym + '_' + '\0'
+ if ((len = (cname != NULL ? strlen(cname) : 0) + strlen(syms[i]) + 2) >
+ FILENAME_MAX) {
+ goto done;
+ }
+ jniEntryName = malloc(len);
+ if (jniEntryName == NULL) {
+ JNU_ThrowOutOfMemoryError(env, NULL);
+ goto done;
+ }
+ strcpy(jniEntryName, syms[i]);
+ if (cname != NULL) {
+ strcat(jniEntryName, "_");
+ strcat(jniEntryName, cname);
+ }
+ entryName = JVM_FindLibraryEntry(handle, jniEntryName);
+ free(jniEntryName);
+ if(entryName) {
+ break;
+ }
+ }
+
+ done:
+ return entryName;
+}
+
+/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: load
- * Signature: (Ljava/lang/String;)J
+ * Signature: (Ljava/lang/String;Z)V
*/
JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_load
- (JNIEnv *env, jobject this, jstring name)
+ (JNIEnv *env, jobject this, jstring name, jboolean isBuiltin)
{
const char *cname;
jint jniVersion;
jthrowable cause;
void * handle;
@@ -325,22 +382,17 @@
return;
cname = JNU_GetStringPlatformChars(env, name, 0);
if (cname == 0)
return;
- handle = JVM_LoadLibrary(cname);
+ handle = isBuiltin ? procHandle : JVM_LoadLibrary(cname);
if (handle) {
const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
JNI_OnLoad_t JNI_OnLoad;
- unsigned int i;
- for (i = 0; i < sizeof(onLoadSymbols) / sizeof(char *); i++) {
- JNI_OnLoad = (JNI_OnLoad_t)
- JVM_FindLibraryEntry(handle, onLoadSymbols[i]);
- if (JNI_OnLoad) {
- break;
- }
- }
+ JNI_OnLoad = (JNI_OnLoad_t)findBuiltinJniFunction(env, handle,
+ isBuiltin ? cname : NULL,
+ JNI_TRUE);
if (JNI_OnLoad) {
JavaVM *jvm;
(*env)->GetJavaVM(env, &jvm);
jniVersion = (*JNI_OnLoad)(jvm, NULL);
} else {
@@ -353,11 +405,12 @@
(*env)->Throw(env, cause);
JVM_UnloadLibrary(handle);
goto done;
}
- if (!JVM_IsSupportedJNIVersion(jniVersion)) {
+ if (!JVM_IsSupportedJNIVersion(jniVersion) ||
+ (isBuiltin && jniVersion < JNI_VERSION_1_8)) {
char msg[256];
jio_snprintf(msg, sizeof(msg),
"unsupported JNI version 0x%08X required by %s",
jniVersion, cname);
JNU_ThrowByName(env, "java/lang/UnsatisfiedLinkError", msg);
@@ -373,53 +426,53 @@
(*env)->Throw(env, cause);
}
goto done;
}
(*env)->SetLongField(env, this, handleID, ptr_to_jlong(handle));
+ (*env)->SetBooleanField(env, this, loadedID, JNI_TRUE);
done:
JNU_ReleaseStringPlatformChars(env, name, cname);
}
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: unload
- * Signature: ()V
+ * Signature: (Z)V
*/
JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_unload
- (JNIEnv *env, jobject this)
+(JNIEnv *env, jobject this, jstring name, jboolean isBuiltin)
{
const char *onUnloadSymbols[] = JNI_ONUNLOAD_SYMBOLS;
void *handle;
JNI_OnUnload_t JNI_OnUnload;
- unsigned int i;
+ const char *cname;
if (!initIDs(env))
return;
-
- handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID));
- for (i = 0; i < sizeof(onUnloadSymbols) / sizeof(char *); i++) {
- JNI_OnUnload = (JNI_OnUnload_t )
- JVM_FindLibraryEntry(handle, onUnloadSymbols[i]);
- if (JNI_OnUnload) {
- break;
- }
+ cname = JNU_GetStringPlatformChars(env, name, 0);
+ if (cname == NULL) {
+ return;
}
-
+ handle = jlong_to_ptr((*env)->GetLongField(env, this, handleID));
+ JNI_OnUnload = (JNI_OnUnload_t )findBuiltinJniFunction(env, handle,
+ isBuiltin ? cname : NULL,
+ JNI_FALSE);
if (JNI_OnUnload) {
JavaVM *jvm;
(*env)->GetJavaVM(env, &jvm);
(*JNI_OnUnload)(jvm, NULL);
}
JVM_UnloadLibrary(handle);
+ JNU_ReleaseStringPlatformChars(env, name, cname);
}
/*
* Class: java_lang_ClassLoader_NativeLibrary
* Method: find
- * Signature: (Ljava/lang/String;J)J
+ * Signature: (Ljava/lang/String;)J
*/
JNIEXPORT jlong JNICALL
Java_java_lang_ClassLoader_00024NativeLibrary_find
(JNIEnv *env, jobject this, jstring name)
{
@@ -454,5 +507,63 @@
return (*env)->GetObjectArrayElement(env, jcallerStack, index);
}
return NULL;
}
+/*
+ * Class: java_lang_ClassLoader_NativeLibrary
+ * Method: findBuiltinLib
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_java_lang_ClassLoader_00024NativeLibrary_findBuiltinLib
+ (JNIEnv *env, jclass cls, jstring name)
+{
+ const char *cname;
+ char *libName;
+ int prefixLen = (int) strlen(JNI_LIB_PREFIX);
+ int suffixLen = (int) strlen(JNI_LIB_SUFFIX);
+ int len;
+ jstring lib;
+ void *ret;
+ const char *onLoadSymbols[] = JNI_ONLOAD_SYMBOLS;
+
+ if (name == NULL) {
+ JNU_ThrowInternalError(env, "NULL filename for native library");
+ return NULL;
+ }
+ // Can't call initIDs because it will recurse into NativeLibrary via
+ // FindClass to check context so set prochandle here as well.
+ procHandle = getProcessHandle();
+ cname = JNU_GetStringPlatformChars(env, name, 0);
+ if (cname == NULL) {
+ return NULL;
+ }
+ // Copy name Skipping PREFIX
+ len = strlen(cname);
+ if (len <= (prefixLen+suffixLen)) {
+ JNU_ReleaseStringPlatformChars(env, name, cname);
+ return NULL;
+ }
+ libName = malloc(len + 1); //+1 for null if prefix+suffix == 0
+ if (libName == NULL) {
+ JNU_ThrowOutOfMemoryError(env, NULL);
+ return NULL;
+ }
+ if (len > prefixLen) {
+ strcpy(libName, cname+prefixLen);
+ }
+ JNU_ReleaseStringPlatformChars(env, name, cname);
+
+ // Strip SUFFIX
+ libName[strlen(libName)-suffixLen] = '\0';
+
+ // Check for JNI_OnLoad_libname function
+ ret = findBuiltinJniFunction(env, procHandle, libName, JNI_TRUE);
+ if (ret != NULL) {
+ lib = JNU_NewStringPlatform(env, libName);
+ free(libName);
+ return lib;
+ }
+ free(libName);
+ return NULL;
+}