Skip to content

Commit da5a980

Browse files
jonpryorradekdoulik
authored andcommitted
[Java.Interop, java-interop] java_interop_jvm_load error handling
Two problems were found via manual review of `java_interop_jvm_load()`: 1. If `path` is loaded but required symbols cannot be found, the loaded library is never closed, which could be a resource leak. 2. If `path` *can't* be loaded, there's no easy way to determine *why* it couldn't be loaded, because **dlerror**(3) isn't called. Fix (1) by closing the loaded library before freeing `jvm`. Fix (2) by renaming `java_interop_jvm_load()` to `java_interop_jvm_load_with_error_message()`, which takes an "optional" `char**` parameter which will hold the `dlerror()` output if the library cannot be loaded: const char *path = …; char *error; int status = java_interop_jvm_load_with_error_message (path, &error); if (status != 0) { fprintf (stderr, "Could not load `%s`: %s\n", path, error); java_interop_free (error); } The value of `error` must be freed with `java_interop_free()`.
1 parent 03dacfb commit da5a980

File tree

3 files changed

+25
-4
lines changed

3 files changed

+25
-4
lines changed

src/Java.Runtime.Environment/Java.Interop/JreRuntime.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,12 @@ static unsafe JreRuntimeOptions CreateJreVM (JreRuntimeOptions builder)
8686
return builder;
8787

8888
if (!string.IsNullOrEmpty (builder.JvmLibraryPath)) {
89-
int r = NativeMethods.java_interop_jvm_load (builder.JvmLibraryPath);
89+
IntPtr errorPtr = IntPtr.Zero;
90+
int r = NativeMethods.java_interop_jvm_load_with_error_message (builder.JvmLibraryPath, out errorPtr);
9091
if (r != 0) {
91-
throw new Exception ($"Could not load JVM path `{builder.JvmLibraryPath}` ({r})!");
92+
string error = Marshal.PtrToStringAnsi (errorPtr);
93+
NativeMethods.java_interop_free (errorPtr);
94+
throw new Exception ($"Could not load JVM path `{builder.JvmLibraryPath}`: {error} ({r})!");
9295
}
9396
}
9497

@@ -154,7 +157,10 @@ protected override void Dispose (bool disposing)
154157

155158
partial class NativeMethods {
156159
[DllImport (JavaInteropLib, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
157-
internal static extern int java_interop_jvm_load (string path);
160+
internal static extern void java_interop_free (IntPtr p);
161+
162+
[DllImport (JavaInteropLib, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
163+
internal static extern int java_interop_jvm_load_with_error_message (string path, out IntPtr message);
158164

159165
[DllImport (JavaInteropLib, CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)]
160166
internal static extern int java_interop_jvm_create (out IntPtr javavm, out IntPtr jnienv, ref JavaVMInitArgs args);

src/java-interop/java-interop-jvm.cc

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,12 @@ struct DylibJVM {
1818
static struct DylibJVM *jvm;
1919

2020
int
21-
java_interop_jvm_load (const char *path)
21+
java_interop_jvm_load_with_error_message (const char *path, char **error_message)
2222
{
23+
if (error_message) {
24+
*error_message = NULL;
25+
}
26+
2327
if (jvm != NULL) {
2428
return JAVA_INTEROP_JVM_FAILED_ALREADY_LOADED;
2529
}
@@ -31,6 +35,9 @@ java_interop_jvm_load (const char *path)
3135

3236
jvm->dl_handle = dlopen (path, RTLD_LAZY);
3337
if (!jvm->dl_handle) {
38+
if (error_message) {
39+
*error_message = java_interop_strdup (dlerror ());
40+
}
3441
free (jvm);
3542
jvm = NULL;
3643
return JAVA_INTEROP_JVM_FAILED_NOT_LOADED;
@@ -54,6 +61,7 @@ java_interop_jvm_load (const char *path)
5461
#undef LOAD_SYMBOL
5562

5663
if (symbols_missing) {
64+
dlclose (jvm->dl_handle);
5765
free (jvm);
5866
jvm = NULL;
5967
return JAVA_INTEROP_JVM_FAILED_SYMBOL_MISSING;
@@ -62,6 +70,12 @@ java_interop_jvm_load (const char *path)
6270
return 0;
6371
}
6472

73+
int
74+
java_interop_jvm_load (const char *path)
75+
{
76+
return java_interop_jvm_load_with_error_message (path, NULL);
77+
}
78+
6579
#define ji_return_val_if_fail(expr, val) do { if (!(expr)) return (val); } while (0)
6680

6781
int java_interop_jvm_create (JavaVM **p_vm, void **p_env, void *vm_args)

src/java-interop/java-interop-jvm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ JAVA_INTEROP_BEGIN_DECLS
1414
#define JAVA_INTEROP_JVM_FAILED_SYMBOL_MISSING (JAVA_INTEROP_JVM_FAILED-4)
1515

1616
MONO_API int java_interop_jvm_load (const char *path);
17+
MONO_API int java_interop_jvm_load_with_error_message (const char *path, char **error);
1718
MONO_API int java_interop_jvm_create (JavaVM **p_vm, void **p_env, void *vm_args);
1819
MONO_API int java_interop_jvm_list (JavaVM **vmBuf, int bufLen, int *nVMs);
1920

0 commit comments

Comments
 (0)