|
|
78a2f7 |
From 47461c8bd7427432bc0afe848db001e05f8d01a3 Mon Sep 17 00:00:00 2001
|
|
|
78a2f7 |
From: Jakub Filak <jfilak@redhat.com>
|
|
|
78a2f7 |
Date: Wed, 15 Jan 2014 11:49:36 +0100
|
|
|
78a2f7 |
Subject: [PATCH 24/39] Do not report exceptions caught by native methods
|
|
|
78a2f7 |
|
|
|
78a2f7 |
Related to rhbz#1051198
|
|
|
78a2f7 |
---
|
|
|
78a2f7 |
src/abrt-checker.c | 247 ++++++++++++++++++++++++++++++++++++++++-------------
|
|
|
78a2f7 |
src/jthread_map.c | 26 +++---
|
|
|
78a2f7 |
src/jthread_map.h | 18 ++--
|
|
|
78a2f7 |
3 files changed, 212 insertions(+), 79 deletions(-)
|
|
|
78a2f7 |
|
|
|
78a2f7 |
diff --git a/src/abrt-checker.c b/src/abrt-checker.c
|
|
|
78a2f7 |
index d5160cb..fb0c0eb 100644
|
|
|
78a2f7 |
--- a/src/abrt-checker.c
|
|
|
78a2f7 |
+++ b/src/abrt-checker.c
|
|
|
78a2f7 |
@@ -63,9 +63,6 @@
|
|
|
78a2f7 |
/* Enables checks based on JVMTI_EVENT_VM_DEATH */
|
|
|
78a2f7 |
/* #define ABRT_VM_DEATH_CHECK */
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-/* Enables checks based on JVMTI_EVENT_EXCEPTION_CATCH */
|
|
|
78a2f7 |
-/* #define ABRT_EXCEPTION_CATCH_CHECK */
|
|
|
78a2f7 |
-
|
|
|
78a2f7 |
/* Enables checks based on JVMTI_EVENT_VM_OBJECT_ALLOC */
|
|
|
78a2f7 |
/* #define ABRT_OBJECT_ALLOCATION_SIZE_CHECK */
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -165,6 +162,19 @@ typedef struct {
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
/*
|
|
|
78a2f7 |
+ * This structure is representation of a single report of an exception.
|
|
|
78a2f7 |
+ */
|
|
|
78a2f7 |
+typedef struct {
|
|
|
78a2f7 |
+ char *message;
|
|
|
78a2f7 |
+ char *stacktrace;
|
|
|
78a2f7 |
+ char *executable;
|
|
|
78a2f7 |
+ char *exception_type_name;
|
|
|
78a2f7 |
+ jobject exception_object;
|
|
|
78a2f7 |
+} T_exceptionReport;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+/*
|
|
|
78a2f7 |
* Flags for specification of destination for error reports
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
typedef enum {
|
|
|
78a2f7 |
@@ -214,6 +224,9 @@ int executableFlags = 0;
|
|
|
78a2f7 |
/* Map of buffer for already reported exceptions to prevent re-reporting */
|
|
|
78a2f7 |
T_jthreadMap *threadMap;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
+/* Map of uncaught exceptions. There should be only 1 per thread.*/
|
|
|
78a2f7 |
+T_jthreadMap *uncaughtExceptionMap;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
|
|
|
78a2f7 |
/* forward headers */
|
|
|
78a2f7 |
static char* get_path_to_class(jvmtiEnv *jvmti_env, JNIEnv *jni_env, jclass class, char *class_name, const char *stringize_method_name);
|
|
|
78a2f7 |
@@ -453,9 +466,12 @@ static int exception_is_intended_to_be_reported(
|
|
|
78a2f7 |
|
|
|
78a2f7 |
if (reportedCaughExceptionTypes != NULL)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- *exception_type = get_exception_type_name(jvmti_env, jni_env, exception_object);
|
|
|
78a2f7 |
if (NULL == *exception_type)
|
|
|
78a2f7 |
- return 0;
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ *exception_type = get_exception_type_name(jvmti_env, jni_env, exception_object);
|
|
|
78a2f7 |
+ if (NULL == *exception_type)
|
|
|
78a2f7 |
+ return 0;
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
|
|
|
78a2f7 |
/* special cases for selected exceptions */
|
|
|
78a2f7 |
for (char **cursor = reportedCaughExceptionTypes; *cursor; ++cursor)
|
|
|
78a2f7 |
@@ -1277,7 +1293,7 @@ static void JNICALL callback_on_thread_start(
|
|
|
78a2f7 |
return;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- jthread_map_push(threadMap, tid, threads_exc_buf);
|
|
|
78a2f7 |
+ jthread_map_push(threadMap, tid, (void *)threads_exc_buf);
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -1304,7 +1320,25 @@ static void JNICALL callback_on_thread_end(
|
|
|
78a2f7 |
return;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- T_jthrowableCircularBuf *threads_exc_buf = jthread_map_pop(threadMap, tid);
|
|
|
78a2f7 |
+ T_exceptionReport *rpt = (T_exceptionReport *)jthread_map_pop(uncaughtExceptionMap, tid);
|
|
|
78a2f7 |
+ T_jthrowableCircularBuf *threads_exc_buf = (T_jthrowableCircularBuf *)jthread_map_pop(threadMap, tid);
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ if (NULL != rpt)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ if (NULL == threads_exc_buf || NULL == jthrowable_circular_buf_find(threads_exc_buf, rpt->exception_object))
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ report_stacktrace(NULL != rpt->executable ? rpt->executable : processProperties.main_class,
|
|
|
78a2f7 |
+ NULL != rpt->message ? rpt->message : "Uncaught exception",
|
|
|
78a2f7 |
+ rpt->stacktrace,
|
|
|
78a2f7 |
+ NULL != threads_exc_buf);
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ free(rpt->message);
|
|
|
78a2f7 |
+ free(rpt->stacktrace);
|
|
|
78a2f7 |
+ free(rpt->executable);
|
|
|
78a2f7 |
+ free(rpt->exception_type_name);
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
if (threads_exc_buf != NULL)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
jthrowable_circular_buf_free(threads_exc_buf);
|
|
|
78a2f7 |
@@ -2120,7 +2154,7 @@ static void JNICALL callback_on_exception(
|
|
|
78a2f7 |
|
|
|
78a2f7 |
if (NULL != threadMap && 0 == get_tid(jni_env, thr, &tid))
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- threads_exc_buf = jthread_map_get(threadMap, tid);
|
|
|
78a2f7 |
+ threads_exc_buf = (T_jthrowableCircularBuf *)jthread_map_get(threadMap, tid);
|
|
|
78a2f7 |
VERBOSE_PRINT("Got circular buffer for thread %p\n", (void *)threads_exc_buf);
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
else
|
|
|
78a2f7 |
@@ -2137,12 +2171,6 @@ static void JNICALL callback_on_exception(
|
|
|
78a2f7 |
char *class_name_ptr = NULL;
|
|
|
78a2f7 |
char *class_signature_ptr = NULL;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- if (NULL != threads_exc_buf)
|
|
|
78a2f7 |
- {
|
|
|
78a2f7 |
- VERBOSE_PRINT("Pushing to circular buffer\n");
|
|
|
78a2f7 |
- jthrowable_circular_buf_push(threads_exc_buf, exception_object);
|
|
|
78a2f7 |
- }
|
|
|
78a2f7 |
-
|
|
|
78a2f7 |
error_code = (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name_ptr, &method_signature_ptr, NULL);
|
|
|
78a2f7 |
if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
goto callback_on_exception_cleanup;
|
|
|
78a2f7 |
@@ -2176,11 +2204,47 @@ static void JNICALL callback_on_exception(
|
|
|
78a2f7 |
if (NULL == report_message)
|
|
|
78a2f7 |
report_message = (NULL != catch_method) ? "Caught exception" : "Uncaught exception";
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- report_stacktrace(NULL != executable ? executable : processProperties.main_class,
|
|
|
78a2f7 |
- report_message,
|
|
|
78a2f7 |
- stack_trace_str,
|
|
|
78a2f7 |
- NULL != threads_exc_buf);
|
|
|
78a2f7 |
+ if (NULL == catch_method)
|
|
|
78a2f7 |
+ { /* Postpone reporting of uncaught exceptions as they may be caught by a native function */
|
|
|
78a2f7 |
+ T_exceptionReport *rpt = malloc(sizeof(*rpt));
|
|
|
78a2f7 |
+ if (NULL == rpt)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ fprintf(stderr, __FILE__ ":" STRINGIZE(__LINE__) ": malloc(): out of memory");
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ else
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ rpt->message = message;
|
|
|
78a2f7 |
+ message = NULL;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ rpt->exception_type_name = exception_type_name;
|
|
|
78a2f7 |
+ exception_type_name = NULL;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ rpt->stacktrace = stack_trace_str;
|
|
|
78a2f7 |
+ stack_trace_str = NULL;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ rpt->executable = executable;
|
|
|
78a2f7 |
+ executable = NULL;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
+ rpt->exception_object = exception_object;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ jthread_map_push(uncaughtExceptionMap, tid, (T_exceptionReport *)rpt);
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ else
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ report_stacktrace(NULL != executable ? executable : processProperties.main_class,
|
|
|
78a2f7 |
+ report_message,
|
|
|
78a2f7 |
+ stack_trace_str,
|
|
|
78a2f7 |
+ NULL != threads_exc_buf);
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ if (NULL != threads_exc_buf)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ VERBOSE_PRINT("Pushing to circular buffer\n");
|
|
|
78a2f7 |
+ jthrowable_circular_buf_push(threads_exc_buf, exception_object);
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ free(executable);
|
|
|
78a2f7 |
free(message);
|
|
|
78a2f7 |
free(stack_trace_str);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -2217,18 +2281,16 @@ callback_on_exception_cleanup:
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-
|
|
|
78a2f7 |
-#if ABRT_EXCEPTION_CATCH_CHECK
|
|
|
78a2f7 |
/*
|
|
|
78a2f7 |
* This function is called when an exception is catched.
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
static void JNICALL callback_on_exception_catch(
|
|
|
78a2f7 |
jvmtiEnv *jvmti_env,
|
|
|
78a2f7 |
- JNIEnv *jni_env __UNUSED_VAR,
|
|
|
78a2f7 |
- jthread thr __UNUSED_VAR,
|
|
|
78a2f7 |
+ JNIEnv *jni_env,
|
|
|
78a2f7 |
+ jthread thread,
|
|
|
78a2f7 |
jmethodID method,
|
|
|
78a2f7 |
jlocation location __UNUSED_VAR,
|
|
|
78a2f7 |
- jobject exception __UNUSED_VAR)
|
|
|
78a2f7 |
+ jobject exception_object)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
jvmtiError error_code;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -2236,52 +2298,120 @@ static void JNICALL callback_on_exception_catch(
|
|
|
78a2f7 |
char *method_signature_ptr = NULL;
|
|
|
78a2f7 |
char *class_signature_ptr = NULL;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- jclass class;
|
|
|
78a2f7 |
-
|
|
|
78a2f7 |
/* all operations should be processed in critical section */
|
|
|
78a2f7 |
enter_critical_section(jvmti_env, shared_lock);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- /* retrieve all required informations */
|
|
|
78a2f7 |
- error_code = (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name_ptr, &method_signature_ptr, NULL);
|
|
|
78a2f7 |
- if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
- goto callback_on_exception_catch_cleanup;
|
|
|
78a2f7 |
-
|
|
|
78a2f7 |
- error_code = (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, &class);
|
|
|
78a2f7 |
- if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
- goto callback_on_exception_catch_cleanup;
|
|
|
78a2f7 |
+ jclass class;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- error_code = (*jvmti_env)->GetClassSignature(jvmti_env, class, &class_signature_ptr, NULL);
|
|
|
78a2f7 |
- if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
- goto callback_on_exception_catch_cleanup;
|
|
|
78a2f7 |
+ jlong tid = 0;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-#ifdef VERBOSE
|
|
|
78a2f7 |
- /* readable class name */
|
|
|
78a2f7 |
- char *class_name_ptr = format_class_name(class_signature_ptr, '.');
|
|
|
78a2f7 |
-#endif
|
|
|
78a2f7 |
+ if (get_tid(jni_env, thread, &tid))
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ fprintf(stderr, __FILE__ ":" STRINGIZE(__LINE__) ": Cannot clear uncaught exceptions");
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_exit;
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- VERBOSE_PRINT("An exception was caught in a method %s%s() with signature %s\n", class_name_ptr, method_name_ptr, method_signature_ptr);
|
|
|
78a2f7 |
+ T_exceptionReport *rpt = (T_exceptionReport *)jthread_map_get(uncaughtExceptionMap, tid);
|
|
|
78a2f7 |
+ if (NULL == rpt)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_exit;
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-callback_on_exception_catch_cleanup:
|
|
|
78a2f7 |
- /* cleapup */
|
|
|
78a2f7 |
- if (method_name_ptr != NULL)
|
|
|
78a2f7 |
+ jclass object_class = (*jni_env)->FindClass(jni_env, "java/lang/Object");
|
|
|
78a2f7 |
+ if (NULL == object_class)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- error_code = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)method_name_ptr);
|
|
|
78a2f7 |
- check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__));
|
|
|
78a2f7 |
+ VERBOSE_PRINT("Cannot find java/lang/Object class");
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_exit;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
- if (method_signature_ptr != NULL)
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ jmethodID equal_method = (*jni_env)->GetMethodID(jni_env, object_class, "equals", "(Ljava/lang/Object;)Z");
|
|
|
78a2f7 |
+ if (NULL == equal_method)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- error_code = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)method_signature_ptr);
|
|
|
78a2f7 |
- check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__));
|
|
|
78a2f7 |
+ VERBOSE_PRINT("Cannot find java.lang.Object.equals(Ljava/lang/Object;)Z method");
|
|
|
78a2f7 |
+ (*jni_env)->DeleteLocalRef(jni_env, object_class);
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_exit;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
- if (class_signature_ptr != NULL)
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ jboolean equal_objects = (*jni_env)->CallBooleanMethod(jni_env, exception_object, equal_method, rpt->exception_object);
|
|
|
78a2f7 |
+ if (!equal_objects)
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_exit;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ /* Faster than get()-pop() approach is faster because it is search-and-search-free but
|
|
|
78a2f7 |
+ * pop()-push() approach is search-free-and-search-malloc
|
|
|
78a2f7 |
+ *
|
|
|
78a2f7 |
+ * JVM always catches java.security.PrivilegedActionException while
|
|
|
78a2f7 |
+ * handling uncaught java.lang.ClassNotFoundException throw by
|
|
|
78a2f7 |
+ * initialization of the system (native) class loader.
|
|
|
78a2f7 |
+ */
|
|
|
78a2f7 |
+ jthread_map_pop(uncaughtExceptionMap, tid);
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ if (exception_is_intended_to_be_reported(jvmti_env, jni_env, rpt->exception_object, &(rpt->exception_type_name)))
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- error_code = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)class_signature_ptr);
|
|
|
78a2f7 |
- check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__));
|
|
|
78a2f7 |
+ jlong tid = 0;
|
|
|
78a2f7 |
+ T_jthrowableCircularBuf *threads_exc_buf = NULL;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ if (NULL != threadMap && 0 == get_tid(jni_env, thread, &tid))
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ threads_exc_buf = (T_jthrowableCircularBuf *)jthread_map_get(threadMap, tid);
|
|
|
78a2f7 |
+ VERBOSE_PRINT("Got circular buffer for thread %p\n", (void *)threads_exc_buf);
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ else
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ VERBOSE_PRINT("Cannot get thread's ID. Disabling reporting to ABRT.");
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ if (NULL == threads_exc_buf || NULL == jthrowable_circular_buf_find(threads_exc_buf, rpt->exception_object))
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ /* retrieve all required informations */
|
|
|
78a2f7 |
+ error_code = (*jvmti_env)->GetMethodName(jvmti_env, method, &method_name_ptr, &method_signature_ptr, NULL);
|
|
|
78a2f7 |
+ if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_cleanup;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ error_code = (*jvmti_env)->GetMethodDeclaringClass(jvmti_env, method, &class);
|
|
|
78a2f7 |
+ if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_cleanup;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ error_code = (*jvmti_env)->GetClassSignature(jvmti_env, class, &class_signature_ptr, NULL);
|
|
|
78a2f7 |
+ if (check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__)))
|
|
|
78a2f7 |
+ goto callback_on_exception_catch_cleanup;
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ /* readable class name */
|
|
|
78a2f7 |
+ char *class_name_ptr = format_class_name(class_signature_ptr, '\0');
|
|
|
78a2f7 |
+ char *message = format_exception_reason_message(/*caught*/1, rpt->exception_type_name, class_name_ptr, method_name_ptr);
|
|
|
78a2f7 |
+ report_stacktrace(NULL != rpt->executable ? rpt->executable : processProperties.main_class,
|
|
|
78a2f7 |
+ NULL != message ? message : "Caught exception",
|
|
|
78a2f7 |
+ rpt->stacktrace,
|
|
|
78a2f7 |
+ NULL != threads_exc_buf);
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+ if (NULL != threads_exc_buf)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ VERBOSE_PRINT("Pushing to circular buffer\n");
|
|
|
78a2f7 |
+ jthrowable_circular_buf_push(threads_exc_buf, rpt->exception_object);
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+callback_on_exception_catch_cleanup:
|
|
|
78a2f7 |
+ /* cleapup */
|
|
|
78a2f7 |
+ if (method_name_ptr != NULL)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ error_code = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)method_name_ptr);
|
|
|
78a2f7 |
+ check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__));
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ if (class_signature_ptr != NULL)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ error_code = (*jvmti_env)->Deallocate(jvmti_env, (unsigned char *)class_signature_ptr);
|
|
|
78a2f7 |
+ check_jvmti_error(jvmti_env, error_code, __FILE__ ":" STRINGIZE(__LINE__));
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
+ free(rpt->message);
|
|
|
78a2f7 |
+ free(rpt->stacktrace);
|
|
|
78a2f7 |
+ free(rpt->executable);
|
|
|
78a2f7 |
+ free(rpt->exception_type_name);
|
|
|
78a2f7 |
+
|
|
|
78a2f7 |
+callback_on_exception_catch_exit:
|
|
|
78a2f7 |
exit_critical_section(jvmti_env, shared_lock);
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
-#endif /* ABRT_EXCEPTION_CATCH_CHECK */
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -2497,10 +2627,8 @@ jvmtiError register_all_callback_functions(jvmtiEnv *jvmti_env)
|
|
|
78a2f7 |
/* JVMTI_EVENT_EXCEPTION */
|
|
|
78a2f7 |
callbacks.Exception = &callback_on_exception;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-#if ABRT_EXCEPTION_CATCH_CHECK
|
|
|
78a2f7 |
/* JVMTI_EVENT_EXCEPTION_CATCH */
|
|
|
78a2f7 |
callbacks.ExceptionCatch = &callback_on_exception_catch;
|
|
|
78a2f7 |
-#endif /* ABRT_EXCEPTION_CATCH_CHECK */
|
|
|
78a2f7 |
|
|
|
78a2f7 |
#if ABRT_OBJECT_ALLOCATION_SIZE_CHECK
|
|
|
78a2f7 |
/* JVMTI_EVENT_VM_OBJECT_ALLOC */
|
|
|
78a2f7 |
@@ -2580,12 +2708,10 @@ jvmtiError set_event_notification_modes(jvmtiEnv* jvmti_env)
|
|
|
78a2f7 |
return error_code;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-#if ABRT_EXCEPTION_CATCH_CHECK
|
|
|
78a2f7 |
if ((error_code = set_event_notification_mode(jvmti_env, JVMTI_EVENT_EXCEPTION_CATCH)) != JNI_OK)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
return error_code;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
-#endif /* ABRT_EXCEPTION_CATCH_CHECK */
|
|
|
78a2f7 |
|
|
|
78a2f7 |
#if ABRT_OBJECT_ALLOCATION_SIZE_CHECK
|
|
|
78a2f7 |
if ((error_code = set_event_notification_mode(jvmti_env, JVMTI_EVENT_VM_OBJECT_ALLOC)) != JNI_OK)
|
|
|
78a2f7 |
@@ -2903,6 +3029,12 @@ JNIEXPORT jint JNICALL Agent_OnLoad(
|
|
|
78a2f7 |
return -1;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
+ uncaughtExceptionMap = jthread_map_new();
|
|
|
78a2f7 |
+ if (NULL == uncaughtExceptionMap)
|
|
|
78a2f7 |
+ {
|
|
|
78a2f7 |
+ fprintf(stderr, __FILE__ ":" STRINGIZE(__LINE__) ": can not create a set of uncaught exceptions\n");
|
|
|
78a2f7 |
+ return -1;
|
|
|
78a2f7 |
+ }
|
|
|
78a2f7 |
return JNI_OK;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -2928,6 +3060,7 @@ JNIEXPORT void JNICALL Agent_OnUnload(JavaVM *vm __UNUSED_VAR)
|
|
|
78a2f7 |
fclose(fout);
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
+ jthread_map_free(uncaughtExceptionMap);
|
|
|
78a2f7 |
jthread_map_free(threadMap);
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
diff --git a/src/jthread_map.c b/src/jthread_map.c
|
|
|
78a2f7 |
index 29c5c29..cd5ca52 100644
|
|
|
78a2f7 |
--- a/src/jthread_map.c
|
|
|
78a2f7 |
+++ b/src/jthread_map.c
|
|
|
78a2f7 |
@@ -35,7 +35,7 @@ struct jthread_map_item;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
typedef struct jthread_map_item {
|
|
|
78a2f7 |
long tid; ///< item ID from Thread.getId()
|
|
|
78a2f7 |
- T_jthrowableCircularBuf *buffer; ///< an instance of circular buffer for thread
|
|
|
78a2f7 |
+ void *data; ///< data
|
|
|
78a2f7 |
struct jthread_map_item *next; ///< a next item mapped to same element
|
|
|
78a2f7 |
} T_jthreadMapItem;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -76,7 +76,7 @@ void jthread_map_free(T_jthreadMap *map)
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-static T_jthreadMapItem *jthrowable_map_item_new(long tid, T_jthrowableCircularBuf *buffer)
|
|
|
78a2f7 |
+static T_jthreadMapItem *jthrowable_map_item_new(long tid, void *item)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
T_jthreadMapItem *itm = malloc(sizeof(*itm));
|
|
|
78a2f7 |
if (NULL == itm)
|
|
|
78a2f7 |
@@ -86,7 +86,7 @@ static T_jthreadMapItem *jthrowable_map_item_new(long tid, T_jthrowableCircularB
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
itm->tid = tid;
|
|
|
78a2f7 |
- itm->buffer = buffer;
|
|
|
78a2f7 |
+ itm->data = item;
|
|
|
78a2f7 |
itm->next = NULL;
|
|
|
78a2f7 |
return itm;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
@@ -105,7 +105,7 @@ static void jthread_map_item_free(T_jthreadMapItem *itm)
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-void jthread_map_push(T_jthreadMap *map, jlong tid, T_jthrowableCircularBuf *buffer)
|
|
|
78a2f7 |
+void jthread_map_push(T_jthreadMap *map, jlong tid, void *item)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
assert(NULL != map);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -122,7 +122,7 @@ void jthread_map_push(T_jthreadMap *map, jlong tid, T_jthrowableCircularBuf *buf
|
|
|
78a2f7 |
|
|
|
78a2f7 |
if (NULL == itm)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- T_jthreadMapItem *new = jthrowable_map_item_new(tid, buffer);
|
|
|
78a2f7 |
+ T_jthreadMapItem *new = jthrowable_map_item_new(tid, item);
|
|
|
78a2f7 |
if (last == NULL)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
map->items[index] = new;
|
|
|
78a2f7 |
@@ -138,39 +138,39 @@ void jthread_map_push(T_jthreadMap *map, jlong tid, T_jthrowableCircularBuf *buf
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-T_jthrowableCircularBuf *jthread_map_get(T_jthreadMap *map, jlong tid)
|
|
|
78a2f7 |
+void *jthread_map_get(T_jthreadMap *map, jlong tid)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
assert(NULL != map);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
pthread_mutex_lock(&map->mutex);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
const size_t index = tid % MAP_SIZE;
|
|
|
78a2f7 |
- T_jthrowableCircularBuf *buffer = NULL;
|
|
|
78a2f7 |
+ void *data = NULL;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
for (T_jthreadMapItem *itm = map->items[index]; NULL != itm; itm = itm->next)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
if (itm->tid == tid)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- buffer = itm->buffer;
|
|
|
78a2f7 |
+ data = itm->data;
|
|
|
78a2f7 |
break;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
pthread_mutex_unlock(&map->mutex);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- return buffer;
|
|
|
78a2f7 |
+ return data;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
-T_jthrowableCircularBuf *jthread_map_pop(T_jthreadMap *map, jlong tid)
|
|
|
78a2f7 |
+void *jthread_map_pop(T_jthreadMap *map, jlong tid)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
assert(NULL != map);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
pthread_mutex_lock(&map->mutex);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
const size_t index = tid % MAP_SIZE;
|
|
|
78a2f7 |
- T_jthrowableCircularBuf *buffer = NULL;
|
|
|
78a2f7 |
+ void *data = NULL;
|
|
|
78a2f7 |
if (NULL != map->items[index])
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
T_jthreadMapItem *last = NULL;
|
|
|
78a2f7 |
@@ -183,7 +183,7 @@ T_jthrowableCircularBuf *jthread_map_pop(T_jthreadMap *map, jlong tid)
|
|
|
78a2f7 |
|
|
|
78a2f7 |
if (NULL != itm)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
- buffer = itm->buffer;
|
|
|
78a2f7 |
+ data = itm->data;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
if (NULL == last)
|
|
|
78a2f7 |
{
|
|
|
78a2f7 |
@@ -200,7 +200,7 @@ T_jthrowableCircularBuf *jthread_map_pop(T_jthreadMap *map, jlong tid)
|
|
|
78a2f7 |
|
|
|
78a2f7 |
pthread_mutex_unlock(&map->mutex);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
- return buffer;
|
|
|
78a2f7 |
+ return data;
|
|
|
78a2f7 |
}
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
diff --git a/src/jthread_map.h b/src/jthread_map.h
|
|
|
78a2f7 |
index 29fcc92..52d2832 100644
|
|
|
78a2f7 |
--- a/src/jthread_map.h
|
|
|
78a2f7 |
+++ b/src/jthread_map.h
|
|
|
78a2f7 |
@@ -23,7 +23,7 @@
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
/*
|
|
|
78a2f7 |
- * Map of TID to jthrowable_circular_buf
|
|
|
78a2f7 |
+ * Map of TID to (void *)
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
typedef struct jthread_map T_jthreadMap;
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -41,7 +41,7 @@ T_jthreadMap *jthread_map_new();
|
|
|
78a2f7 |
/*
|
|
|
78a2f7 |
* Frees map's memory
|
|
|
78a2f7 |
*
|
|
|
78a2f7 |
- * Doesn't release memory of stored circular buffers.
|
|
|
78a2f7 |
+ * Doesn't release memory of stored (void *).
|
|
|
78a2f7 |
*
|
|
|
78a2f7 |
* @param map Pointer to @jthread_map. Accepts NULL
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
@@ -50,15 +50,15 @@ void jthread_map_free(T_jthreadMap *map);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
/*
|
|
|
78a2f7 |
- * Adds a new map item identified by @tid with value @buffer
|
|
|
78a2f7 |
+ * Adds a new map item identified by @tid with value @item
|
|
|
78a2f7 |
*
|
|
|
78a2f7 |
* Does nothing if item with same @tid already exists in @map
|
|
|
78a2f7 |
*
|
|
|
78a2f7 |
* @param map Map
|
|
|
78a2f7 |
* @param tid New item ID
|
|
|
78a2f7 |
- * @param buffer A pointer to @jthrowable_circular_buf
|
|
|
78a2f7 |
+ * @param item A (void *) item
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
-void jthread_map_push(T_jthreadMap *map, jlong tid, T_jthrowableCircularBuf *buffer);
|
|
|
78a2f7 |
+void jthread_map_push(T_jthreadMap *map, jlong tid, void *item);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -67,9 +67,9 @@ void jthread_map_push(T_jthreadMap *map, jlong tid, T_jthrowableCircularBuf *buf
|
|
|
78a2f7 |
*
|
|
|
78a2f7 |
* @param map Map
|
|
|
78a2f7 |
* @param tid Required ID
|
|
|
78a2f7 |
- * @returns A pointer to stored @jthrowable_circular_buf or NULL if item with @tid was not found
|
|
|
78a2f7 |
+ * @returns A stored item or NULL if item with @tid was not found
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
-T_jthrowableCircularBuf *jthread_map_get(T_jthreadMap *map, jlong tid);
|
|
|
78a2f7 |
+void *jthread_map_get(T_jthreadMap *map, jlong tid);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
@@ -78,9 +78,9 @@ T_jthrowableCircularBuf *jthread_map_get(T_jthreadMap *map, jlong tid);
|
|
|
78a2f7 |
*
|
|
|
78a2f7 |
* @param map Map
|
|
|
78a2f7 |
* @param tid Removed item's ID
|
|
|
78a2f7 |
- * @returns A pointer to stored @jthrowable_circular_buf or NULL if item with @tid was not found
|
|
|
78a2f7 |
+ * @returns A stored item or NULL if item with @tid was not found
|
|
|
78a2f7 |
*/
|
|
|
78a2f7 |
-T_jthrowableCircularBuf *jthread_map_pop(T_jthreadMap *map, jlong tid);
|
|
|
78a2f7 |
+void *jthread_map_pop(T_jthreadMap *map, jlong tid);
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
|
|
|
78a2f7 |
--
|
|
|
78a2f7 |
1.8.3.1
|
|
|
78a2f7 |
|