fixing small leak on exception on the transport-epoll-native allocation
Motivation: the JNI function ThrowNew won't release any allocated memory. The method exceptionMessage is allocating a new string concatenating 2 constant strings What is creating a small leak in case of these exceptions are happening. Modifications: Added new methods that will use exceptionMessage and free resources accordingly. I am also removing the inline definition on these methods as they could be reused by other added modules (e.g. libaio which should be coming soon) Result: No more leaks in case of failures.
This commit is contained in:
parent
895ceb72a3
commit
c0e889ae54
23
transport-native-epoll/src/main/c/exception_helper.h
Normal file
23
transport-native-epoll/src/main/c/exception_helper.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2015 The Netty Project
|
||||||
|
*
|
||||||
|
* The Netty Project licenses this file to you under the Apache License,
|
||||||
|
* version 2.0 (the "License"); you may not use this file except in compliance
|
||||||
|
* with the License. You may obtain a copy of the License at:
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||||
|
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||||
|
* License for the specific language governing permissions and limitations
|
||||||
|
* under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void throwRuntimeException(JNIEnv* env, char* message);
|
||||||
|
void throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
||||||
|
void throwIOException(JNIEnv* env, char* message);
|
||||||
|
void throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber);
|
||||||
|
void throwClosedChannelException(JNIEnv* env);
|
||||||
|
void throwOutOfMemoryError(JNIEnv* env);
|
||||||
|
char* exceptionMessage(char* msg, int error);
|
@ -33,6 +33,7 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include "io_netty_channel_epoll_Native.h"
|
#include "io_netty_channel_epoll_Native.h"
|
||||||
|
#include "exception_helper.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* On older Linux kernels, epoll can't handle timeout
|
* On older Linux kernels, epoll can't handle timeout
|
||||||
@ -93,25 +94,46 @@ static int socketType;
|
|||||||
static const char* ip4prefix = "::ffff:";
|
static const char* ip4prefix = "::ffff:";
|
||||||
|
|
||||||
// util methods
|
// util methods
|
||||||
static inline void throwRuntimeException(JNIEnv* env, char* message) {
|
void throwRuntimeException(JNIEnv* env, char* message) {
|
||||||
(*env)->ThrowNew(env, runtimeExceptionClass, message);
|
(*env)->ThrowNew(env, runtimeExceptionClass, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void throwIOException(JNIEnv* env, char* message) {
|
void throwRuntimeExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) {
|
||||||
|
char* allocatedMessage = exceptionMessage(message, errorNumber);
|
||||||
|
(*env)->ThrowNew(env, runtimeExceptionClass, allocatedMessage);
|
||||||
|
free(allocatedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void throwIOException(JNIEnv* env, char* message) {
|
||||||
(*env)->ThrowNew(env, ioExceptionClass, message);
|
(*env)->ThrowNew(env, ioExceptionClass, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void throwClosedChannelException(JNIEnv* env) {
|
void throwIOExceptionErrorNo(JNIEnv* env, char* message, int errorNumber) {
|
||||||
|
char* allocatedMessage = exceptionMessage(message, errorNumber);
|
||||||
|
(*env)->ThrowNew(env, ioExceptionClass, allocatedMessage);
|
||||||
|
free(allocatedMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void throwClosedChannelException(JNIEnv* env) {
|
||||||
jobject exception = (*env)->NewObject(env, closedChannelExceptionClass, closedChannelExceptionMethodId);
|
jobject exception = (*env)->NewObject(env, closedChannelExceptionClass, closedChannelExceptionMethodId);
|
||||||
(*env)->Throw(env, exception);
|
(*env)->Throw(env, exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void throwOutOfMemoryError(JNIEnv* env) {
|
void throwOutOfMemoryError(JNIEnv* env) {
|
||||||
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
|
jclass exceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
|
||||||
(*env)->ThrowNew(env, exceptionClass, "");
|
(*env)->ThrowNew(env, exceptionClass, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char* exceptionMessage(char* msg, int error) {
|
/** Notice: every usage of exceptionMessage needs to release the allocated memory for the sequence of char */
|
||||||
|
char* exceptionMessage(char* msg, int error) {
|
||||||
|
if (error < 0) {
|
||||||
|
// some functions return negative values
|
||||||
|
// and it's hard to keep track of when to send -error and when not
|
||||||
|
// this will just take care when things are forgotten
|
||||||
|
// what would generate a proper error
|
||||||
|
error = error * -1;
|
||||||
|
}
|
||||||
|
//strerror is returning a constant, so no need to free anything coming from strerror
|
||||||
char* err = strerror(error);
|
char* err = strerror(error);
|
||||||
char* result = malloc(strlen(msg) + strlen(err) + 1);
|
char* result = malloc(strlen(msg) + strlen(err) + 1);
|
||||||
strcpy(result, msg);
|
strcpy(result, msg);
|
||||||
@ -136,7 +158,7 @@ static inline jint getOption(JNIEnv* env, jint fd, int level, int optname, void*
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int err = errno;
|
int err = errno;
|
||||||
throwRuntimeException(env, exceptionMessage("getsockopt() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "getsockopt() failed: ", err);
|
||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -144,7 +166,7 @@ static inline int setOption(JNIEnv* env, jint fd, int level, int optname, const
|
|||||||
int rc = setsockopt(fd, level, optname, optval, len);
|
int rc = setsockopt(fd, level, optname, optval, len);
|
||||||
if (rc < 0) {
|
if (rc < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
throwRuntimeException(env, exceptionMessage("setsockopt() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "setsockopt() failed: ", err);
|
||||||
}
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -615,7 +637,7 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_eventFd(JNIEnv* env, j
|
|||||||
|
|
||||||
if (eventFD < 0) {
|
if (eventFD < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
throwRuntimeException(env, exceptionMessage("eventfd() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "eventfd() failed: ", err);
|
||||||
}
|
}
|
||||||
return eventFD;
|
return eventFD;
|
||||||
}
|
}
|
||||||
@ -625,7 +647,7 @@ JNIEXPORT void JNICALL Java_io_netty_channel_epoll_Native_eventFdWrite(JNIEnv* e
|
|||||||
|
|
||||||
if (eventFD < 0) {
|
if (eventFD < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
throwRuntimeException(env, exceptionMessage("eventfd_write() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "eventfd_write() failed: ", err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -649,9 +671,9 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollCreate(JNIEnv* en
|
|||||||
if (efd < 0) {
|
if (efd < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
if (epoll_create1) {
|
if (epoll_create1) {
|
||||||
throwRuntimeException(env, exceptionMessage("epoll_create1() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "epoll_create1() failed: ", err);
|
||||||
} else {
|
} else {
|
||||||
throwRuntimeException(env, exceptionMessage("epoll_create() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "epoll_create() failed: ", err);
|
||||||
}
|
}
|
||||||
return efd;
|
return efd;
|
||||||
}
|
}
|
||||||
@ -659,7 +681,7 @@ JNIEXPORT jint JNICALL Java_io_netty_channel_epoll_Native_epollCreate(JNIEnv* en
|
|||||||
if (fcntl(efd, F_SETFD, FD_CLOEXEC) < 0) {
|
if (fcntl(efd, F_SETFD, FD_CLOEXEC) < 0) {
|
||||||
int err = errno;
|
int err = errno;
|
||||||
close(efd);
|
close(efd);
|
||||||
throwRuntimeException(env, exceptionMessage("fcntl() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "fcntl() failed: ", err);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -856,7 +878,7 @@ static inline jobject recvFrom0(JNIEnv* env, jint fd, void* buffer, jint pos, ji
|
|||||||
throwClosedChannelException(env);
|
throwClosedChannelException(env);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
throwIOException(env, exceptionMessage("recvfrom() failed: ", err));
|
throwIOExceptionErrorNo(env, "recvfrom() failed: ", err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1375,7 +1397,7 @@ JNIEXPORT jstring JNICALL Java_io_netty_channel_epoll_Native_kernelVersion(JNIEn
|
|||||||
return (*env)->NewStringUTF(env, name.release);
|
return (*env)->NewStringUTF(env, name.release);
|
||||||
}
|
}
|
||||||
int err = errno;
|
int err = errno;
|
||||||
throwRuntimeException(env, exceptionMessage("uname() failed: ", err));
|
throwRuntimeExceptionErrorNo(env, "uname() failed: ", err);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user