Fix JNI local references leaks

This commit is contained in:
emanuele-f 2022-08-13 14:26:56 +02:00
parent 2a0f99067a
commit 0cfcafaea9
4 changed files with 54 additions and 11 deletions

View File

@ -134,7 +134,6 @@ public class ConnectionDescriptor {
src_port = _src_port;
dst_port = _dst_port;
local_port = _local_port;
Log.d("ConnectionDescriptor", "local_port=" + local_port);
uid = _uid;
ifidx = _ifidx;
first_seen = last_seen = when;

View File

@ -19,7 +19,7 @@
#ifdef ANDROID
#include <jni.h>
#include "jni_utils.h"
#include "common/utils.h"
/* ******************************************************* */
@ -37,6 +37,16 @@ int jniCheckException(JNIEnv *env) {
/* ******************************************************* */
// Dumps JNI reference tables to logcat to detect possible reference leaks
void jniDumpReferences(JNIEnv *env) {
jclass vm_class = jniFindClass(env, "dalvik/system/VMDebug");
jmethodID dump_mid = jniGetStaticMethodID(env, vm_class, "dumpReferenceTables", "()V" );
(*env)->CallStaticVoidMethod(env, vm_class, dump_mid);
(*env)->DeleteLocalRef(env, vm_class);
}
/* ******************************************************* */
jclass jniFindClass(JNIEnv *env, const char *name) {
jclass cls = (*env)->FindClass(env, name);
if (cls == NULL)
@ -60,6 +70,18 @@ jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *
/* ******************************************************* */
jmethodID jniGetStaticMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature) {
jmethodID method = (*env)->GetStaticMethodID(env, cls, name, signature);
if (method == NULL) {
log_e("Static method %s %s not found", name, signature);
jniCheckException(env);
}
return method;
}
/* ******************************************************* */
jfieldID jniFieldID(JNIEnv *env, jclass cls, const char *name, const char *type) {
jfieldID field = (*env)->GetFieldID(env, cls, name, type);
if(field == NULL) {
@ -93,6 +115,7 @@ jobject jniEnumVal(JNIEnv *env, const char *class_name, const char *enum_key) {
jniCheckException(env);
}
(*env)->DeleteLocalRef(env, cls);
return val;
}

View File

@ -26,9 +26,11 @@
jclass jniFindClass(JNIEnv *env, const char *name);
jmethodID jniGetMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature);
jmethodID jniGetStaticMethodID(JNIEnv *env, jclass cls, const char *name, const char *signature);
jfieldID jniFieldID(JNIEnv *env, jclass cls, const char *name, const char *type);
jobject jniEnumVal(JNIEnv *env, const char *class_name, const char *enum_key);
int jniCheckException(JNIEnv *env);
void jniDumpReferences(JNIEnv *env);
#else // if ANDROID

View File

@ -315,7 +315,7 @@ cleanup:
/* ******************************************************* */
// Load information about the blacklists to use (pd->malware_detection.bls_info)
// Load information about the blacklists to use (into pd->malware_detection.bls_info)
static int loadBlacklistsInfo(pcapdroid_t *pd) {
int rv = 0;
JNIEnv *env = pd->env;
@ -353,6 +353,7 @@ static int loadBlacklistsInfo(pcapdroid_t *pd) {
(*pd->env)->DeleteLocalRef(pd->env, bl_type);
//log_d("[+] Blacklist: %s (%s)", blinfo->fname, (blinfo->type == IP_BLACKLIST) ? "IP" : "domain");
(*pd->env)->DeleteLocalRef(pd->env, bl_descr);
}
}
@ -380,19 +381,21 @@ static void notifyBlacklistsLoaded(pcapdroid_t *pd, bl_status_arr_t *status_arr)
jobject stats = (*env)->NewObject(env, cls.blacklist_status, mids.blacklistStatusInit,
fname, st->num_rules);
if((stats == NULL) || jniCheckException(env)) {
(*env)->DeleteLocalRef(env, fname);
(*env)->DeleteLocalRef(env, fname);
if((stats == NULL) || jniCheckException(env))
break;
}
(*env)->SetObjectArrayElement(env, status_obj, i, stats);
(*env)->DeleteLocalRef(env, stats);
if(jniCheckException(env)) {
(*env)->DeleteLocalRef(env, stats);
break;
}
}
(*pd->env)->CallVoidMethod(pd->env, pd->capture_service, mids.notifyBlacklistsLoaded, status_obj);
(*env)->CallVoidMethod(env, pd->capture_service, mids.notifyBlacklistsLoaded, status_obj);
(*env)->DeleteLocalRef(env, status_obj);
}
/* ******************************************************* */
@ -402,7 +405,7 @@ static bool dumpPayloadChunk(struct pcapdroid *pd, const pkt_context_t *pctx, in
bool rv = false;
if(pctx->data->payload_chunks == NULL) {
pctx->data->payload_chunks = (*pd->env)->NewObject(pd->env, cls.arraylist, mids.arraylistNew);
pctx->data->payload_chunks = (*env)->NewObject(env, cls.arraylist, mids.arraylistNew);
if((pctx->data->payload_chunks == NULL) || jniCheckException(env))
return false;
}
@ -413,10 +416,10 @@ static bool dumpPayloadChunk(struct pcapdroid *pd, const pkt_context_t *pctx, in
jobject chunk_type = (pctx->data->l7proto == NDPI_PROTOCOL_HTTP) ? enums.chunktype_http : enums.chunktype_raw;
jobject chunk = (*pd->env)->NewObject(pd->env, cls.payload_chunk, mids.payloadChunkInit, barray, chunk_type, pctx->is_tx, pctx->ms);
jobject chunk = (*env)->NewObject(env, cls.payload_chunk, mids.payloadChunkInit, barray, chunk_type, pctx->is_tx, pctx->ms);
if(chunk && !jniCheckException(env)) {
(*env)->SetByteArrayRegion(env, barray, 0, dump_size, (jbyte*)pctx->pkt->l7);
rv = (*pd->env)->CallBooleanMethod(pd->env, pctx->data->payload_chunks, mids.arraylistAdd, chunk);
rv = (*env)->CallBooleanMethod(env, pctx->data->payload_chunks, mids.arraylistAdd, chunk);
}
//log_d("Dump chunk [size=%d]: %d", rv, dump_size);
@ -441,6 +444,7 @@ static void getLibprogPath(pcapdroid_t *pd, const char *prog_name, char *buf, in
}
jstring obj = (*env)->CallObjectMethod(env, pd->capture_service, mids.getLibprogPath, prog_str);
(*env)->DeleteLocalRef(env, prog_str);
if(!jniCheckException(env)) {
const char *value = (*env)->GetStringUTFChars(env, obj, 0);
@ -603,6 +607,21 @@ Java_com_emanuelef_remote_1capture_CaptureService_runPacketLoop(JNIEnv *env, jcl
global_pd = NULL;
logcallback = NULL;
#if 0
// free JNI local objects to ease references leak detection
for(int i=0; i<sizeof(cls)/sizeof(jclass); i++) {
jclass cur = ((jclass*)&cls)[i];
(*env)->DeleteLocalRef(env, cur);
}
for(int i=0; i<sizeof(enums)/sizeof(jobject); i++) {
jobject cur = ((jobject*)&enums)[i];
(*env)->DeleteLocalRef(env, cur);
}
// at this point the local reference table should only contain 2 entries (VMDebug + Thread)
jniDumpReferences(env);
#endif
#ifdef PCAPDROID_TRACK_ALLOCS
log_i(get_allocs_summary());
#endif