8208303: Track JNI failures and fail tests
authorjcbeyler
Wed, 08 Aug 2018 15:34:32 -0700
changeset 51340 818768cd1c6c
parent 51339 554bb4e2d10d
child 51341 09cc8813ae51
8208303: Track JNI failures and fail tests Summary: Fail in native code via FatalException to signal test failure Reviewed-by: amenkov, sspitsyn
test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.c
--- a/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.c	Wed Aug 08 14:40:02 2018 -0700
+++ b/test/hotspot/jtreg/serviceability/jvmti/HeapMonitor/libHeapMonitorTest.c	Wed Aug 08 15:34:32 2018 -0700
@@ -34,10 +34,16 @@
 #ifndef JNI_ENV_ARG
 
 #ifdef __cplusplus
-#define JNI_ENV_ARG(x, y) y
+#define JNI_ENV_ARG(x)
+#define JNI_ENV_ARG2(x, y) y
+#define JNI_ENV_ARG3(x, y, z) y, z
+#define JNI_ENV_ARG4(x, y, z, w) y, z, w
 #define JNI_ENV_PTR(x) x
 #else
-#define JNI_ENV_ARG(x,y) x, y
+#define JNI_ENV_ARG(x) x
+#define JNI_ENV_ARG2(x, y) x, y
+#define JNI_ENV_ARG3(x, y, z) x, y, z
+#define JNI_ENV_ARG4(x, y, z, w) x, y, z, w
 #define JNI_ENV_PTR(x) (*x)
 #endif
 
@@ -283,39 +289,129 @@
 }
 
 // Static native API for various tests.
-static void fill_native_frames(JNIEnv* env, jobjectArray frames,
-                               ExpectedContentFrame* native_frames, size_t size) {
+static int fill_native_frames(JNIEnv* env, jobjectArray frames,
+                              ExpectedContentFrame* native_frames, size_t size) {
   size_t i;
   for (i = 0; i < size; i++) {
-    jobject obj = (*env)->GetObjectArrayElement(env, frames, (jsize) i);
-    jclass frame_class = (*env)->GetObjectClass(env, obj);
-    jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class,
-                                                       "lineNumber", "I");
-    int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
+    jclass frame_class = NULL;
+    jfieldID line_number_field_id = 0;
+    int line_number = 0;
+    jfieldID string_id = 0;
+    jstring string_object = NULL;
+    const char* method = NULL;
+    const char* file_name = NULL;
+    const char* signature = NULL;
+
+    jobject obj = JNI_ENV_PTR(env)->GetObjectArrayElement(
+        JNI_ENV_ARG3(env, frames, (jsize) i));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetObjectArrayElement\n");
+      return -1;
+    }
+
+    frame_class = JNI_ENV_PTR(env)->GetObjectClass(JNI_ENV_ARG2(env, obj));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetObjectClass\n");
+      return -1;
+    }
+
+    line_number_field_id =
+        JNI_ENV_PTR(env)->GetFieldID(JNI_ENV_ARG4(env, frame_class, "lineNumber", "I"));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
+      return -1;
+    }
+
+    line_number = JNI_ENV_PTR(env)->GetIntField(JNI_ENV_ARG3(env, obj, line_number_field_id));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetIntField\n");
+      return -1;
+    }
+
+    string_id = JNI_ENV_PTR(env)->GetFieldID(
+        JNI_ENV_ARG4(env, frame_class, "method", "Ljava/lang/String;"));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
+      return -1;
+    }
+
+    string_object = (jstring) JNI_ENV_PTR(env)->GetObjectField(
+        JNI_ENV_ARG3(env, obj, string_id));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetObjectField\n");
+      return -1;
+    }
 
-    jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method",
-                                            "Ljava/lang/String;");
-    jstring string_object = (jstring) (*env)->GetObjectField(env, obj,
-                                                             string_id);
-    const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
-    const char* file_name;
-    const char* signature;
+    method = JNI_ENV_PTR(env)->GetStringUTFChars(JNI_ENV_ARG3(env, string_object, 0));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "Exception in jni GetStringUTFChars\n");
+      return -1;
+    }
+
+    string_id = JNI_ENV_PTR(env)->GetFieldID(
+        JNI_ENV_ARG4(env, frame_class, "fileName", "Ljava/lang/String;"));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "Exception in jni GetFieldID\n");
+      return -1;
+    }
+
+    string_object =
+        (jstring) (JNI_ENV_PTR(env)->GetObjectField(
+            JNI_ENV_ARG3(env, obj, string_id)));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in second jni GetObjectField\n");
+      return -1;
+    }
+
+    file_name = JNI_ENV_PTR(env)->GetStringUTFChars(
+        JNI_ENV_ARG3(env, string_object, 0));
 
-    string_id = (*env)->GetFieldID(env, frame_class, "fileName",
-                                   "Ljava/lang/String;");
-    string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
-    file_name = (*env)->GetStringUTFChars(env, string_object, 0);
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
+      return -1;
+    }
+
+    string_id = JNI_ENV_PTR(env)->GetFieldID(
+        JNI_ENV_ARG4(env, frame_class, "signature", "Ljava/lang/String;"));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in second jni GetFieldID\n");
+      return -1;
+    }
 
-    string_id = (*env)->GetFieldID(env, frame_class, "signature",
-                                   "Ljava/lang/String;");
-    string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
-    signature= (*env)->GetStringUTFChars(env, string_object, 0);
+    string_object =
+        (jstring) (JNI_ENV_PTR(env)->GetObjectField(
+            JNI_ENV_ARG3(env, obj, string_id)));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in third jni GetObjectField\n");
+      return -1;
+    }
+
+    signature = JNI_ENV_PTR(env)->GetStringUTFChars(
+        JNI_ENV_ARG3(env, string_object, 0));
+
+    if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+      fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
+      return -1;
+    }
 
     native_frames[i].name = method;
     native_frames[i].file_name = file_name;
     native_frames[i].signature = signature;
     native_frames[i].line_number = line_number;
   }
+
+  return 0;
 }
 
 // Internal storage system implementation.
@@ -465,6 +561,11 @@
     live_object->thread = thread;
     live_object->object = (*jni)->NewWeakGlobalRef(jni, object);
 
+    if (JNI_ENV_PTR(jni)->ExceptionOccurred(JNI_ENV_ARG(jni))) {
+      JNI_ENV_PTR(jni)->FatalError(
+          JNI_ENV_ARG2(jni, "Error in event_storage_add: Exception in jni NewWeakGlobalRef"));
+    }
+
     // Only now lock and get things done quickly.
     event_storage_lock(storage);
 
@@ -577,17 +678,6 @@
   return 1;
 }
 
-static jint throw_exception(JNIEnv *env, char *msg) {
-  jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
-
-  if (exc_class == NULL) {
-    fprintf(stderr, "throw_exception: Error in FindClass(env, %s)\n",
-            EXC_CNAME);
-    return -1;
-  }
-  return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
-}
-
 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 
 JNIEXPORT
@@ -781,16 +871,16 @@
   jvmtiEventCallbacks callbacks;
   jvmtiCapabilities caps;
 
-  res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
-                                 JVMTI_VERSION_9);
+  res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG3(jvm, (void **) &jvmti,
+                                 JVMTI_VERSION_9));
   if (res != JNI_OK || jvmti == NULL) {
     fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
     return JNI_ERR;
   }
 
   // Get second jvmti environment.
-  res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &second_jvmti),
-                                 JVMTI_VERSION_9);
+  res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG3(jvm, (void **) &second_jvmti,
+                                 JVMTI_VERSION_9));
   if (res != JNI_OK || second_jvmti == NULL) {
     fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
     return JNI_ERR;
@@ -882,14 +972,25 @@
                                           jobjectArray frames,
                                           jboolean check_lines) {
   jboolean result;
-  jsize size = (*env)->GetArrayLength(env, frames);
-  ExpectedContentFrame *native_frames = malloc(size * sizeof(*native_frames));
+  jsize size = JNI_ENV_PTR(env)->GetArrayLength(JNI_ENV_ARG2(env, frames));
+  ExpectedContentFrame *native_frames;
+
+  if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "obtainedEvents failed with the GetArrayLength call"));
+  }
+
+  native_frames = malloc(size * sizeof(*native_frames));
 
   if (native_frames == NULL) {
-    return 0;
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in obtainedEvents: malloc returned NULL for native_frames allocation\n"));
   }
 
-  fill_native_frames(env, frames, native_frames, size);
+  if (fill_native_frames(env, frames, native_frames, size) != 0) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in obtainedEvents: fill_native_frames returned failed status\n"));
+  }
   result = event_storage_contains(env, &global_event_storage, native_frames,
                                   size, check_lines);
 
@@ -902,14 +1003,25 @@
                                            jobjectArray frames,
                                            jboolean check_lines) {
   jboolean result;
-  jsize size = (*env)->GetArrayLength(env, frames);
-  ExpectedContentFrame *native_frames = malloc(size * sizeof(*native_frames));
+  jsize size = JNI_ENV_PTR(env)->GetArrayLength(JNI_ENV_ARG2(env, frames));
+  ExpectedContentFrame *native_frames;
+
+  if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env))) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "garbageContains failed with the GetArrayLength call"));
+  }
+
+  native_frames = malloc(size * sizeof(*native_frames));
 
   if (native_frames == NULL) {
-    return 0;
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in garbageContains: malloc returned NULL for native_frames allocation\n"));
   }
 
-  fill_native_frames(env, frames, native_frames, size);
+  if (fill_native_frames(env, frames, native_frames, size) != 0) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in garbageContains: fill_native_frames returned failed status\n"));
+  }
   result = event_storage_garbage_contains(env, &global_event_storage,
                                           native_frames, size, check_lines);
 
@@ -1047,25 +1159,31 @@
   return event_storage_number_additions(&global_event_storage);
 }
 
-static void allocate_object(JNIEnv* env) {
+static jobject allocate_object(JNIEnv* env) {
   // Construct an Object.
-  jclass cls = (*env)->FindClass(env, "java/lang/Object");
+  jclass cls = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG2(env, "java/lang/Object"));
   jmethodID constructor;
+  jobject result;
 
-  if (cls == NULL) {
-    throw_exception(env, "Cannot find Object class.");
-    return;
+  if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env)) || cls == NULL) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in jni FindClass: Cannot find Object class\n"));
   }
 
-  constructor = (*env)->GetMethodID(env, cls, "<init>", "()V");
-
-  if (constructor == NULL) {
-    throw_exception(env, "Cannot find Object class constructor.");
-    return;
+  constructor = JNI_ENV_PTR(env)->GetMethodID(JNI_ENV_ARG4(env, cls, "<init>", "()V"));
+  if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env)) || constructor == NULL) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in jni GetMethodID: Cannot find Object class constructor\n"));
   }
 
   // Call back constructor to allocate a new instance, with an int argument
-  (*env)->NewObject(env, cls, constructor);
+  result = JNI_ENV_PTR(env)->NewObject(JNI_ENV_ARG3(env, cls, constructor));
+
+  if (JNI_ENV_PTR(env)->ExceptionOccurred(JNI_ENV_ARG(env)) || result == NULL) {
+    JNI_ENV_PTR(env)->FatalError(
+        JNI_ENV_ARG2(env, "Error in jni NewObject: Cannot allocate an object\n"));
+  }
+  return result;
 }
 
 // Ensure we got a callback for the test.
@@ -1082,7 +1200,9 @@
   // infinite recursion here.
   int i;
   for (i = 0; i < 1000; i++) {
-    allocate_object(jni_env);
+    if (allocate_object(jni_env) == NULL) {
+      JNI_ENV_PTR(jni_env)->FatalError(JNI_ENV_ARG2(jni_env, "allocate_object returned NULL\n"));
+    }
   }
 
   did_recursive_callback_test = 1;
@@ -1103,8 +1223,7 @@
   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
                                               sizeof(jvmtiEventCallbacks)),
                   " Set Event Callbacks")) {
-    throw_exception(env, "Cannot reset the callback.");
-    return;
+    JNI_ENV_PTR(env)->FatalError(JNI_ENV_ARG2(env, "Cannot reset the callback."));
   }
 }