Unregister all previous registered native methods if loading of native code fails… (#10719)

Motivation:

It's important to unload all previous registered native methods when there is a failure during loading the native lib. Failing to do so may lead to an "invalid state" and so may segfault the JVM when trying to call a native method that was previous loaded.

This was observed when two versions of netty-tcnative were on the classpath which had different requirements in terms of linking.

Something like this was reported in he hs log:

```
Instructions: (pc=0x0000000116413bf0)
0x0000000116413bd0:
[error occurred during error reporting (printing registers, top of stack, instructions near pc), id 0xb]

Register to memory mapping:

RAX=0x0000000116413bf0 is an unknown value
RBX={method} {0x000000011422e708} 'aprMajorVersion' '()I' in 'io/netty/internal/tcnative/Library'
RCX=0x000000000000000a is an unknown value
RDX=0x000000000000000a is an unknown value
```

Modifications:

- Unregister previous registered native methods on failure
- Unregister previous registered native methods on on unload of the native lib

Result:

No more segfault caused by invalid state when loading of the native lib fails in between. In this case the user will receive an error now like:
This commit is contained in:
Norman Maurer 2020-10-26 14:15:04 +01:00
parent 56c47e4361
commit 31ffe11e47
20 changed files with 157 additions and 63 deletions

View File

@ -35,6 +35,8 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#define LINUXSOCKET_CLASSNAME "io/netty/channel/epoll/LinuxSocket"
// TCP_FASTOPEN is defined in linux 3.7. We define this here so older kernels can compile.
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
@ -755,7 +757,7 @@ jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix)
}
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/epoll/LinuxSocket",
LINUXSOCKET_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
@ -788,6 +790,8 @@ done:
return ret;
}
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env) {
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_UNLOAD_CLASS(env, peerCredentialsClass);
netty_unix_util_unregister_natives(env, packagePrefix, LINUXSOCKET_CLASSNAME);
}

View File

@ -21,6 +21,6 @@
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_epoll_linuxsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env);
void netty_epoll_linuxsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif

View File

@ -49,6 +49,9 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#define STATICALLY_CLASSNAME "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods"
#define NATIVE_CLASSNAME "io/netty/channel/epoll/Native"
// TCP_FASTOPEN is defined in linux 3.7. We define this here so older kernels can compile.
#ifndef TCP_FASTOPEN
#define TCP_FASTOPEN 23
@ -98,6 +101,7 @@ static jfieldID packetScopeIdFieldId = NULL;
static jfieldID packetPortFieldId = NULL;
static jfieldID packetMemoryAddressFieldId = NULL;
static jfieldID packetCountFieldId = NULL;
static char* staticPackagePrefix = NULL;
// util methods
static int getSysctlValue(const char * property, int* returnValue) {
@ -564,6 +568,8 @@ error:
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int ret = JNI_ERR;
int staticallyRegistered = 0;
int nativeRegistered = 0;
int limitsOnLoadCalled = 0;
int errorsOnLoadCalled = 0;
int filedescriptorOnLoadCalled = 0;
@ -577,11 +583,13 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/epoll/NativeStaticallyReferencedJniMethods",
STATICALLY_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
goto done;
}
staticallyRegistered = 1;
// Register the methods which are not referenced by static member variables
dynamicMethods = createDynamicMethodsTable(packagePrefix);
if (dynamicMethods == NULL) {
@ -590,11 +598,13 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/epoll/Native",
NATIVE_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
}
nativeRegistered = 1;
// Load all c modules that we depend upon
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
goto done;
@ -645,23 +655,29 @@ done:
free(nettyClassName);
if (ret == JNI_ERR) {
if (staticallyRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
}
if (nativeRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
if (limitsOnLoadCalled == 1) {
netty_unix_limits_JNI_OnUnLoad(env);
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
}
if (errorsOnLoadCalled == 1) {
netty_unix_errors_JNI_OnUnLoad(env);
netty_unix_errors_JNI_OnUnLoad(env, packagePrefix);
}
if (filedescriptorOnLoadCalled == 1) {
netty_unix_filedescriptor_JNI_OnUnLoad(env);
netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix);
}
if (socketOnLoadCalled == 1) {
netty_unix_socket_JNI_OnUnLoad(env);
netty_unix_socket_JNI_OnUnLoad(env, packagePrefix);
}
if (bufferOnLoadCalled == 1) {
netty_unix_buffer_JNI_OnUnLoad(env);
netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix);
}
if (linuxsocketOnLoadCalled == 1) {
netty_epoll_linuxsocket_JNI_OnUnLoad(env);
netty_epoll_linuxsocket_JNI_OnUnLoad(env, packagePrefix);
}
packetAddrFieldId = NULL;
packetAddrLenFieldId = NULL;
@ -673,13 +689,13 @@ done:
return ret;
}
static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) {
netty_unix_limits_JNI_OnUnLoad(env);
netty_unix_errors_JNI_OnUnLoad(env);
netty_unix_filedescriptor_JNI_OnUnLoad(env);
netty_unix_socket_JNI_OnUnLoad(env);
netty_unix_buffer_JNI_OnUnLoad(env);
netty_epoll_linuxsocket_JNI_OnUnLoad(env);
static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
netty_unix_errors_JNI_OnUnLoad(env, packagePrefix);
netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix);
netty_unix_socket_JNI_OnUnLoad(env, packagePrefix);
netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix);
netty_epoll_linuxsocket_JNI_OnUnLoad(env, packagePrefix);
packetAddrFieldId = NULL;
packetAddrLenFieldId = NULL;
@ -687,6 +703,9 @@ static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) {
packetPortFieldId = NULL;
packetMemoryAddressFieldId = NULL;
packetCountFieldId = NULL;
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
// Invoked by the JVM when statically linked
@ -712,8 +731,12 @@ static jint JNI_OnLoad_netty_transport_native_epoll0(JavaVM* vm, void* reserved)
}
#endif /* NETTY_BUILD_STATIC */
jint ret = netty_epoll_native_JNI_OnLoad(env, packagePrefix);
free(packagePrefix);
if (ret == JNI_ERR) {
free(packagePrefix);
staticPackagePrefix = NULL;
} else {
staticPackagePrefix = packagePrefix;
}
return ret;
}
@ -723,7 +746,9 @@ static void JNI_OnUnload_netty_transport_native_epoll0(JavaVM* vm, void* reserve
// Something is wrong but nothing we can do about this :(
return;
}
netty_epoll_native_JNI_OnUnLoad(env);
netty_epoll_native_JNI_OnUnLoad(env, staticPackagePrefix);
free(staticPackagePrefix);
staticPackagePrefix = NULL;
}
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT

View File

@ -32,6 +32,8 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#define BSDSOCKET_CLASSNAME "io/netty/channel/kqueue/BsdSocket"
// Those are initialized in the init(...) method and cached for performance reasons
static jclass stringClass = NULL;
static jclass peerCredentialsClass = NULL;
@ -249,7 +251,7 @@ jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
}
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/kqueue/BsdSocket",
BSDSOCKET_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
@ -284,7 +286,9 @@ done:
return ret;
}
void netty_kqueue_bsdsocket_JNI_OnUnLoad(JNIEnv* env) {
void netty_kqueue_bsdsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_UNLOAD_CLASS(env, peerCredentialsClass);
NETTY_UNLOAD_CLASS(env, stringClass);
netty_unix_util_unregister_natives(env, packagePrefix, BSDSOCKET_CLASSNAME);
}

View File

@ -20,6 +20,6 @@
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_kqueue_bsdsocket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_kqueue_bsdsocket_JNI_OnUnLoad(JNIEnv* env);
void netty_kqueue_bsdsocket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_KQUEUE_BSDSOCKET_H_ */

View File

@ -24,6 +24,8 @@
#include "netty_unix_jni.h"
#include "netty_unix_util.h"
#define EVENT_ARRAY_CLASSNAME "io/netty/channel/kqueue/KQueueEventArray"
static void netty_kqueue_eventarray_evSet(JNIEnv* env, jclass clzz, jlong keventAddress, jint ident, jshort filter, jshort flags, jint fflags) {
EV_SET((struct kevent*) keventAddress, ident, filter, flags, fflags, 0, NULL);
}
@ -39,7 +41,7 @@ static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(
jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/kqueue/KQueueEventArray",
EVENT_ARRAY_CLASSNAME,
fixed_method_table,
fixed_method_table_size) != 0) {
return JNI_ERR;
@ -47,5 +49,6 @@ jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix)
return NETTY_JNI_VERSION;
}
void netty_kqueue_eventarray_JNI_OnUnLoad(JNIEnv* env) {
void netty_kqueue_eventarray_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, EVENT_ARRAY_CLASSNAME);
}

View File

@ -20,6 +20,6 @@
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_kqueue_eventarray_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_kqueue_eventarray_JNI_OnUnLoad(JNIEnv* env);
void netty_kqueue_eventarray_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_KQUEUE_EVENTARRAY_H_ */

View File

@ -36,6 +36,9 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#define STATICALLY_CLASSNAME "io/netty/channel/kqueue/KQueueStaticallyReferencedJniMethods"
#define NATIVE_CLASSNAME "io/netty/channel/kqueue/Native"
// Currently only macOS supports EVFILT_SOCK, and it is currently only available in internal APIs.
// To make compiling easier we redefine the values here if they are not present.
#ifdef __APPLE__
@ -68,6 +71,8 @@
static clockid_t waitClockId = 0; // initialized by netty_unix_util_initialize_wait_clock
static char* staticPackagePrefix;
static jint netty_kqueue_native_kqueueCreate(JNIEnv* env, jclass clazz) {
jint kq = kqueue();
if (kq < 0) {
@ -265,6 +270,8 @@ static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(
// JNI Method Registration Table End
static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int staticallyRegistered = 0;
int nativeRegistered = 0;
int limitsOnLoadCalled = 0;
int errorsOnLoadCalled = 0;
int filedescriptorOnLoadCalled = 0;
@ -276,15 +283,19 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/kqueue/KQueueStaticallyReferencedJniMethods",
STATICALLY_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
goto error;
}
staticallyRegistered = 1;
// Register the methods which are not referenced by static member variables
if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/kqueue/Native", fixed_method_table, fixed_method_table_size) != 0) {
if (netty_unix_util_register_natives(env, packagePrefix, NATIVE_CLASSNAME, fixed_method_table, fixed_method_table_size) != 0) {
goto error;
}
nativeRegistered = 1;
// Load all c modules that we depend upon
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
goto error;
@ -330,38 +341,44 @@ static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefi
return NETTY_JNI_VERSION;
error:
if (staticallyRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, STATICALLY_CLASSNAME);
}
if (nativeRegistered == 1) {
netty_unix_util_unregister_natives(env, packagePrefix, NATIVE_CLASSNAME);
}
if (limitsOnLoadCalled == 1) {
netty_unix_limits_JNI_OnUnLoad(env);
netty_unix_limits_JNI_OnUnLoad(env, packagePrefix);
}
if (errorsOnLoadCalled == 1) {
netty_unix_errors_JNI_OnUnLoad(env);
netty_unix_errors_JNI_OnUnLoad(env, packagePrefix);
}
if (filedescriptorOnLoadCalled == 1) {
netty_unix_filedescriptor_JNI_OnUnLoad(env);
netty_unix_filedescriptor_JNI_OnUnLoad(env, packagePrefix);
}
if (socketOnLoadCalled == 1) {
netty_unix_socket_JNI_OnUnLoad(env);
netty_unix_socket_JNI_OnUnLoad(env, packagePrefix);
}
if (bufferOnLoadCalled == 1) {
netty_unix_buffer_JNI_OnUnLoad(env);
netty_unix_buffer_JNI_OnUnLoad(env, packagePrefix);
}
if (bsdsocketOnLoadCalled == 1) {
netty_kqueue_bsdsocket_JNI_OnUnLoad(env);
netty_kqueue_bsdsocket_JNI_OnUnLoad(env, packagePrefix);
}
if (eventarrayOnLoadCalled == 1) {
netty_kqueue_eventarray_JNI_OnUnLoad(env);
netty_kqueue_eventarray_JNI_OnUnLoad(env, packagePrefix);
}
return JNI_ERR;
}
static void netty_kqueue_native_JNI_OnUnLoad(JNIEnv* env) {
netty_unix_limits_JNI_OnUnLoad(env);
netty_unix_errors_JNI_OnUnLoad(env);
netty_unix_filedescriptor_JNI_OnUnLoad(env);
netty_unix_socket_JNI_OnUnLoad(env);
netty_unix_buffer_JNI_OnUnLoad(env);
netty_kqueue_bsdsocket_JNI_OnUnLoad(env);
netty_kqueue_eventarray_JNI_OnUnLoad(env);
static void netty_kqueue_native_JNI_OnUnLoad(JNIEnv* env, const char* staticPackagePrefix) {
netty_unix_limits_JNI_OnUnLoad(env, staticPackagePrefix);
netty_unix_errors_JNI_OnUnLoad(env, staticPackagePrefix);
netty_unix_filedescriptor_JNI_OnUnLoad(env, staticPackagePrefix);
netty_unix_socket_JNI_OnUnLoad(env, staticPackagePrefix);
netty_unix_buffer_JNI_OnUnLoad(env, staticPackagePrefix);
netty_kqueue_bsdsocket_JNI_OnUnLoad(env, staticPackagePrefix);
netty_kqueue_eventarray_JNI_OnUnLoad(env, staticPackagePrefix);
}
static jint JNI_OnLoad_netty_transport_native_kqueue0(JavaVM* vm, void* reserved) {
@ -387,9 +404,12 @@ static jint JNI_OnLoad_netty_transport_native_kqueue0(JavaVM* vm, void* reserved
}
#endif /* NETTY_BUILD_STATIC */
jint ret = netty_kqueue_native_JNI_OnLoad(env, packagePrefix);
// It's safe to call free(...) with a NULL argument as well.
free(packagePrefix);
if (ret == JNI_ERR) {
free(packagePrefix);
staticPackagePrefix = NULL;
} else {
staticPackagePrefix = packagePrefix;
}
return ret;
}
@ -400,7 +420,9 @@ static void JNI_OnUnload_netty_transport_native_kqueue0(JavaVM* vm, void* reserv
// Something is wrong but nothing we can do about this :(
return;
}
netty_kqueue_native_JNI_OnUnLoad(env);
netty_kqueue_native_JNI_OnUnLoad(env, staticPackagePrefix);
free(staticPackagePrefix);
staticPackagePrefix = NULL;
}
// We build with -fvisibility=hidden so ensure we mark everything that needs to be visible with JNIEXPORT

View File

@ -17,6 +17,8 @@
#include "netty_unix_util.h"
#include "netty_unix_buffer.h"
#define BUFFER_CLASSNAME "io/netty/channel/unix/Buffer"
// JNI Registered Methods Begin
static jlong netty_unix_buffer_memoryAddress0(JNIEnv* env, jclass clazz, jobject buffer) {
return (jlong) (*env)->GetDirectBufferAddress(env, buffer);
@ -40,7 +42,7 @@ jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/unix/Buffer",
BUFFER_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
return JNI_ERR;
@ -49,4 +51,6 @@ jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
return NETTY_JNI_VERSION;
}
void netty_unix_buffer_JNI_OnUnLoad(JNIEnv* env) { }
void netty_unix_buffer_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, BUFFER_CLASSNAME);
}

View File

@ -20,6 +20,6 @@
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_unix_buffer_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_unix_buffer_JNI_OnUnLoad(JNIEnv* env);
void netty_unix_buffer_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_UNIX_BUFFER_H_ */

View File

@ -21,6 +21,8 @@
#include "netty_unix_jni.h"
#include "netty_unix_util.h"
#define ERRORS_CLASSNAME "io/netty/channel/unix/ErrorsStaticallyReferencedJniMethods"
static jclass oomErrorClass = NULL;
static jclass runtimeExceptionClass = NULL;
static jclass channelExceptionClass = NULL;
@ -214,7 +216,7 @@ jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/unix/ErrorsStaticallyReferencedJniMethods",
ERRORS_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
return JNI_ERR;
@ -241,7 +243,7 @@ error:
return JNI_ERR;
}
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env) {
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
// delete global references so the GC can collect them
NETTY_UNLOAD_CLASS(env, oomErrorClass);
NETTY_UNLOAD_CLASS(env, runtimeExceptionClass);
@ -249,4 +251,6 @@ void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env) {
NETTY_UNLOAD_CLASS(env, ioExceptionClass);
NETTY_UNLOAD_CLASS(env, portUnreachableExceptionClass);
NETTY_UNLOAD_CLASS(env, closedChannelExceptionClass);
netty_unix_util_unregister_natives(env, packagePrefix, ERRORS_CLASSNAME);
}

View File

@ -29,6 +29,6 @@ void netty_unix_errors_throwOutOfMemoryError(JNIEnv* env);
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_unix_errors_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env);
void netty_unix_errors_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_UNIX_ERRORS_H_ */

View File

@ -26,6 +26,8 @@
#include "netty_unix_jni.h"
#include "netty_unix_util.h"
#define FILEDESCRIPTOR_CLASSNAME "io/netty/channel/unix/FileDescriptor"
static jmethodID posId = NULL;
static jmethodID limitId = NULL;
static jfieldID posFieldId = NULL;
@ -278,7 +280,7 @@ static const jint method_table_size = sizeof(method_table) / sizeof(method_table
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int ret = JNI_ERR;
void* mem = NULL;
if (netty_unix_util_register_natives(env, packagePrefix, "io/netty/channel/unix/FileDescriptor", method_table, method_table_size) != 0) {
if (netty_unix_util_register_natives(env, packagePrefix, FILEDESCRIPTOR_CLASSNAME, method_table, method_table_size) != 0) {
goto done;
}
if ((mem = malloc(1)) == NULL) {
@ -313,4 +315,6 @@ done:
return ret;
}
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env) { }
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, FILEDESCRIPTOR_CLASSNAME);
}

View File

@ -20,6 +20,6 @@
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_unix_filedescriptor_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env);
void netty_unix_filedescriptor_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_UNIX_FILEDESCRIPTOR_H_ */

View File

@ -21,6 +21,8 @@
#include "netty_unix_limits.h"
#include "netty_unix_util.h"
#define LIMITS_CLASSNAME "io/netty/channel/unix/LimitsStaticallyReferencedJniMethods"
// Define IOV_MAX if not found to limit the iov size on writev calls
// See https://github.com/netty/netty/issues/2647
#ifndef IOV_MAX
@ -70,7 +72,7 @@ jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
// We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/unix/LimitsStaticallyReferencedJniMethods",
LIMITS_CLASSNAME,
statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) {
return JNI_ERR;
@ -79,4 +81,6 @@ jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
return NETTY_JNI_VERSION;
}
void netty_unix_limits_JNI_OnUnLoad(JNIEnv* env) { }
void netty_unix_limits_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
netty_unix_util_unregister_natives(env, packagePrefix, LIMITS_CLASSNAME);
}

View File

@ -20,6 +20,6 @@
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_unix_limits_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_unix_limits_JNI_OnUnLoad(JNIEnv* env);
void netty_unix_limits_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_UNIX_LIMITS_H_ */

View File

@ -31,6 +31,7 @@
#include "netty_unix_socket.h"
#include "netty_unix_util.h"
#define SOCKET_CLASSNAME "io/netty/channel/unix/Socket"
// Define SO_REUSEPORT if not found to fix build issues.
// See https://github.com/netty/netty/issues/2558
#ifndef SO_REUSEPORT
@ -1061,7 +1062,7 @@ jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
}
if (netty_unix_util_register_natives(env,
packagePrefix,
"io/netty/channel/unix/Socket",
SOCKET_CLASSNAME,
dynamicMethods,
dynamicMethodsTableSize()) != 0) {
goto done;
@ -1099,7 +1100,9 @@ done:
return ret;
}
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env) {
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix) {
NETTY_UNLOAD_CLASS(env, datagramSocketAddressClass);
NETTY_UNLOAD_CLASS(env, inetSocketAddressClass);
netty_unix_util_unregister_natives(env, packagePrefix, SOCKET_CLASSNAME);
}

View File

@ -34,6 +34,6 @@ void netty_unix_socket_getOptionHandleError(JNIEnv* env, int err);
// JNI initialization hooks. Users of this file are responsible for calling these in the JNI_OnLoad and JNI_OnUnload methods.
jint netty_unix_socket_JNI_OnLoad(JNIEnv* env, const char* packagePrefix);
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env);
void netty_unix_socket_JNI_OnUnLoad(JNIEnv* env, const char* packagePrefix);
#endif /* NETTY_UNIX_SOCKET_H_ */

View File

@ -223,6 +223,22 @@ done:
return ret;
}
jint netty_unix_util_unregister_natives(JNIEnv* env, const char* packagePrefix, const char* className) {
char* nettyClassName = NULL;
int ret = JNI_ERR;
NETTY_PREPEND(packagePrefix, className, nettyClassName, done);
jclass nativeCls = (*env)->FindClass(env, nettyClassName);
if (nativeCls == NULL) {
goto done;
}
ret = (*env)->UnregisterNatives(env, nativeCls);
done:
free(nettyClassName);
return ret;
}
void netty_unix_util_free_dynamic_methods_table(JNINativeMethod* dynamicMethods, jint fixedMethodTableSize, jint fullMethodTableSize) {
if (dynamicMethods != NULL) {
jint i = fixedMethodTableSize;

View File

@ -149,6 +149,7 @@ jboolean netty_unix_util_timespec_subtract_ns(struct timespec* ts, uint64_t nano
* Return type is as defined in https://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/functions.html#wp5833.
*/
jint netty_unix_util_register_natives(JNIEnv* env, const char* packagePrefix, const char* className, const JNINativeMethod* methods, jint numMethods);
jint netty_unix_util_unregister_natives(JNIEnv* env, const char* packagePrefix, const char* className);
void netty_unix_util_free_dynamic_methods_table(JNINativeMethod* dynamicMethods, jint fixedMethodTableSize, jint fullMethodTableSize);
void netty_unix_util_free_dynamic_name(char** dynamicName);