We should call the UnLoad methods when we detect an error during calling OnLoad (#8237)

Motivation:

We should ensure we call *UnLoad when we detect an error during calling *OnLoad and previous *OnLoad calls were succesfull.

Modifications:

Correctly call *UnLoad when needed.

Result:

More correct code and no leaks when an error happens during loading the native lib.
This commit is contained in:
Norman Maurer 2018-08-30 06:56:42 +02:00 committed by GitHub
parent ea626ef8c3
commit b73f785631
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 121 additions and 25 deletions

View File

@ -420,13 +420,20 @@ static void freeDynamicMethodsTable(JNINativeMethod* dynamicMethods) {
// JNI Method Registration Table End // JNI Method Registration Table End
static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int limitsOnLoadCalled = 0;
int errorsOnLoadCalled = 0;
int filedescriptorOnLoadCalled = 0;
int socketOnLoadCalled = 0;
int bufferOnLoadCalled = 0;
int linuxsocketOnLoadCalled = 0;
// We must register the statically referenced methods first! // We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env, if (netty_unix_util_register_natives(env,
packagePrefix, packagePrefix,
"io/netty/channel/epoll/NativeStaticallyReferencedJniMethods", "io/netty/channel/epoll/NativeStaticallyReferencedJniMethods",
statically_referenced_fixed_method_table, statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) { statically_referenced_fixed_method_table_size) != 0) {
return JNI_ERR; goto error;
} }
// Register the methods which are not referenced by static member variables // Register the methods which are not referenced by static member variables
JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix); JNINativeMethod* dynamicMethods = createDynamicMethodsTable(packagePrefix);
@ -436,29 +443,40 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
dynamicMethods, dynamicMethods,
dynamicMethodsTableSize()) != 0) { dynamicMethodsTableSize()) != 0) {
freeDynamicMethodsTable(dynamicMethods); freeDynamicMethodsTable(dynamicMethods);
return JNI_ERR; goto error;
} }
freeDynamicMethodsTable(dynamicMethods); freeDynamicMethodsTable(dynamicMethods);
dynamicMethods = NULL; dynamicMethods = NULL;
// Load all c modules that we depend upon // Load all c modules that we depend upon
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
limitsOnLoadCalled = 1;
if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
errorsOnLoadCalled = 1;
if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
filedescriptorOnLoadCalled = 1;
if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
socketOnLoadCalled = 1;
if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
bufferOnLoadCalled = 1;
if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_epoll_linuxsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
linuxsocketOnLoadCalled = 1;
// Initialize this module // Initialize this module
char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket"); char* nettyClassName = netty_unix_util_prepend(packagePrefix, "io/netty/channel/epoll/NativeDatagramPacketArray$NativeDatagramPacket");
@ -467,37 +485,64 @@ static jint netty_epoll_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix
nettyClassName = NULL; nettyClassName = NULL;
if (nativeDatagramPacketCls == NULL) { if (nativeDatagramPacketCls == NULL) {
// pending exception... // pending exception...
return JNI_ERR; goto error;
} }
packetAddrFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addr", "[B"); packetAddrFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "addr", "[B");
if (packetAddrFieldId == NULL) { if (packetAddrFieldId == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addr"); netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.addr");
return JNI_ERR; goto error;
} }
packetScopeIdFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "scopeId", "I"); packetScopeIdFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "scopeId", "I");
if (packetScopeIdFieldId == NULL) { if (packetScopeIdFieldId == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.scopeId"); netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.scopeId");
return JNI_ERR; goto error;
} }
packetPortFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "port", "I"); packetPortFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "port", "I");
if (packetPortFieldId == NULL) { if (packetPortFieldId == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.port"); netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.port");
return JNI_ERR; goto error;
} }
packetMemoryAddressFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "memoryAddress", "J"); packetMemoryAddressFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "memoryAddress", "J");
if (packetMemoryAddressFieldId == NULL) { if (packetMemoryAddressFieldId == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.memoryAddress"); netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.memoryAddress");
return JNI_ERR; goto error;
} }
packetCountFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "count", "I"); packetCountFieldId = (*env)->GetFieldID(env, nativeDatagramPacketCls, "count", "I");
if (packetCountFieldId == NULL) { if (packetCountFieldId == NULL) {
netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.count"); netty_unix_errors_throwRuntimeException(env, "failed to get field ID: NativeDatagramPacket.count");
return JNI_ERR; goto error;
} }
return NETTY_JNI_VERSION; return NETTY_JNI_VERSION;
error:
if (limitsOnLoadCalled == 1) {
netty_unix_limits_JNI_OnUnLoad(env);
}
if (errorsOnLoadCalled == 1) {
netty_unix_errors_JNI_OnUnLoad(env);
}
if (filedescriptorOnLoadCalled == 1) {
netty_unix_filedescriptor_JNI_OnUnLoad(env);
}
if (socketOnLoadCalled == 1) {
netty_unix_socket_JNI_OnUnLoad(env);
}
if (bufferOnLoadCalled == 1) {
netty_unix_buffer_JNI_OnUnLoad(env);
}
if (linuxsocketOnLoadCalled == 1) {
netty_epoll_linuxsocket_JNI_OnUnLoad(env);
}
packetAddrFieldId = NULL;
packetScopeIdFieldId = NULL;
packetPortFieldId = NULL;
packetMemoryAddressFieldId = NULL;
packetCountFieldId = NULL;
return JNI_ERR;
} }
static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) { static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) {
@ -507,6 +552,12 @@ static void netty_epoll_native_JNI_OnUnLoad(JNIEnv* env) {
netty_unix_socket_JNI_OnUnLoad(env); netty_unix_socket_JNI_OnUnLoad(env);
netty_unix_buffer_JNI_OnUnLoad(env); netty_unix_buffer_JNI_OnUnLoad(env);
netty_epoll_linuxsocket_JNI_OnUnLoad(env); netty_epoll_linuxsocket_JNI_OnUnLoad(env);
packetAddrFieldId = NULL;
packetScopeIdFieldId = NULL;
packetPortFieldId = NULL;
packetMemoryAddressFieldId = NULL;
packetCountFieldId = NULL;
} }
// Invoked by the JVM when statically linked // Invoked by the JVM when statically linked

View File

@ -269,48 +269,93 @@ static const jint fixed_method_table_size = sizeof(fixed_method_table) / sizeof(
// JNI Method Registration Table End // JNI Method Registration Table End
static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) { static jint netty_kqueue_native_JNI_OnLoad(JNIEnv* env, const char* packagePrefix) {
int limitsOnLoadCalled = 0;
int errorsOnLoadCalled = 0;
int filedescriptorOnLoadCalled = 0;
int socketOnLoadCalled = 0;
int bufferOnLoadCalled = 0;
int bsdsocketOnLoadCalled = 0;
int eventarrayOnLoadCalled = 0;
// We must register the statically referenced methods first! // We must register the statically referenced methods first!
if (netty_unix_util_register_natives(env, if (netty_unix_util_register_natives(env,
packagePrefix, packagePrefix,
"io/netty/channel/kqueue/KQueueStaticallyReferencedJniMethods", "io/netty/channel/kqueue/KQueueStaticallyReferencedJniMethods",
statically_referenced_fixed_method_table, statically_referenced_fixed_method_table,
statically_referenced_fixed_method_table_size) != 0) { statically_referenced_fixed_method_table_size) != 0) {
return JNI_ERR; goto error;
} }
// Register the methods which are not referenced by static member variables // 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, "io/netty/channel/kqueue/Native", fixed_method_table, fixed_method_table_size) != 0) {
return JNI_ERR; goto error;
} }
// Load all c modules that we depend upon // Load all c modules that we depend upon
if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_limits_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
limitsOnLoadCalled = 1;
if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_errors_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
errorsOnLoadCalled = 1;
if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_filedescriptor_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
filedescriptorOnLoadCalled = 1;
if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_socket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
socketOnLoadCalled = 1;
if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_unix_buffer_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
bufferOnLoadCalled = 1;
if (netty_kqueue_bsdsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_kqueue_bsdsocket_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
bsdsocketOnLoadCalled = 1;
if (netty_kqueue_eventarray_JNI_OnLoad(env, packagePrefix) == JNI_ERR) { if (netty_kqueue_eventarray_JNI_OnLoad(env, packagePrefix) == JNI_ERR) {
return JNI_ERR; goto error;
} }
eventarrayOnLoadCalled = 1;
// Initialize this module // Initialize this module
if (!netty_unix_util_initialize_wait_clock(&waitClockId)) { if (!netty_unix_util_initialize_wait_clock(&waitClockId)) {
fprintf(stderr, "FATAL: could not find a clock for clock_gettime!\n"); fprintf(stderr, "FATAL: could not find a clock for clock_gettime!\n");
return JNI_ERR; goto error;
} }
return NETTY_JNI_VERSION; return NETTY_JNI_VERSION;
error:
if (limitsOnLoadCalled == 1) {
netty_unix_limits_JNI_OnUnLoad(env);
}
if (errorsOnLoadCalled == 1) {
netty_unix_errors_JNI_OnUnLoad(env);
}
if (filedescriptorOnLoadCalled == 1) {
netty_unix_filedescriptor_JNI_OnUnLoad(env);
}
if (socketOnLoadCalled == 1) {
netty_unix_socket_JNI_OnUnLoad(env);
}
if (bufferOnLoadCalled == 1) {
netty_unix_buffer_JNI_OnUnLoad(env);
}
if (bsdsocketOnLoadCalled == 1) {
netty_kqueue_bsdsocket_JNI_OnUnLoad(env);
}
if (eventarrayOnLoadCalled == 1) {
netty_kqueue_eventarray_JNI_OnUnLoad(env);
}
return JNI_ERR;
} }
static void netty_kqueue_native_JNI_OnUnLoad(JNIEnv* env) { static void netty_kqueue_native_JNI_OnUnLoad(JNIEnv* env) {