8080406: VM_GetOrSetLocal doesn't check local slot type against requested type
authorsspitsyn
Thu, 08 Nov 2018 00:07:48 -0800
changeset 52445 a1eb4f1b94c1
parent 52444 5b82f10dc823
child 52446 187d16766a63
8080406: VM_GetOrSetLocal doesn't check local slot type against requested type Summary: Provide possible type checks when LVT is absent Reviewed-by: jcbeyler, cjplummer
src/hotspot/share/prims/jvmtiImpl.cpp
src/hotspot/share/prims/jvmtiImpl.hpp
test/hotspot/jtreg/serviceability/jvmti/GetLocalVariable/GetLocalVars.java
test/hotspot/jtreg/serviceability/jvmti/GetLocalVariable/libGetLocalVars.cpp
test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal003/getlocal003.cpp
test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal004/getlocal004.cpp
--- a/src/hotspot/share/prims/jvmtiImpl.cpp	Thu Nov 08 02:47:50 2018 +0100
+++ b/src/hotspot/share/prims/jvmtiImpl.cpp	Thu Nov 08 00:07:48 2018 -0800
@@ -635,18 +635,8 @@
 //   JVMTI_ERROR_TYPE_MISMATCH
 // Returns: 'true' - everything is Ok, 'false' - error code
 
-bool VM_GetOrSetLocal::check_slot_type(javaVFrame* jvf) {
+bool VM_GetOrSetLocal::check_slot_type_lvt(javaVFrame* jvf) {
   Method* method_oop = jvf->method();
-  if (!method_oop->has_localvariable_table()) {
-    // Just to check index boundaries
-    jint extra_slot = (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0;
-    if (_index < 0 || _index + extra_slot >= method_oop->max_locals()) {
-      _result = JVMTI_ERROR_INVALID_SLOT;
-      return false;
-    }
-    return true;
-  }
-
   jint num_entries = method_oop->localvariable_table_length();
   if (num_entries == 0) {
     _result = JVMTI_ERROR_INVALID_SLOT;
@@ -711,6 +701,35 @@
   return true;
 }
 
+bool VM_GetOrSetLocal::check_slot_type_no_lvt(javaVFrame* jvf) {
+  Method* method_oop = jvf->method();
+  jint extra_slot = (_type == T_LONG || _type == T_DOUBLE) ? 1 : 0;
+
+  if (_index < 0 || _index + extra_slot >= method_oop->max_locals()) {
+    _result = JVMTI_ERROR_INVALID_SLOT;
+    return false;
+  }
+  StackValueCollection *locals = _jvf->locals();
+  BasicType slot_type = locals->at(_index)->type();
+
+  if (slot_type == T_CONFLICT) {
+    _result = JVMTI_ERROR_INVALID_SLOT;
+    return false;
+  }
+  if (extra_slot) {
+    BasicType extra_slot_type = locals->at(_index + 1)->type();
+    if (extra_slot_type != T_INT) {
+      _result = JVMTI_ERROR_INVALID_SLOT;
+      return false;
+    }
+  }
+  if (_type != slot_type && (_type == T_OBJECT || slot_type != T_INT)) {
+    _result = JVMTI_ERROR_TYPE_MISMATCH;
+    return false;
+  }
+  return true;
+}
+
 static bool can_be_deoptimized(vframe* vf) {
   return (vf->is_compiled_frame() && vf->fr().can_be_deoptimized());
 }
@@ -719,8 +738,9 @@
   _jvf = get_java_vframe();
   NULL_CHECK(_jvf, false);
 
-  if (_jvf->method()->is_native()) {
-    if (getting_receiver() && !_jvf->method()->is_static()) {
+  Method* method_oop = _jvf->method();
+  if (method_oop->is_native()) {
+    if (getting_receiver() && !method_oop->is_static()) {
       return true;
     } else {
       _result = JVMTI_ERROR_OPAQUE_FRAME;
@@ -728,8 +748,10 @@
     }
   }
 
-  if (!check_slot_type(_jvf)) {
-    return false;
+  if (method_oop->has_localvariable_table()) {
+    return check_slot_type_lvt(_jvf);
+  } else {
+    return check_slot_type_no_lvt(_jvf);
   }
   return true;
 }
@@ -796,12 +818,6 @@
     } else {
       StackValueCollection *locals = _jvf->locals();
 
-      if (locals->at(_index)->type() == T_CONFLICT) {
-        memset(&_value, 0, sizeof(_value));
-        _value.l = NULL;
-        return;
-      }
-
       switch (_type) {
         case T_INT:    _value.i = locals->int_at   (_index);   break;
         case T_LONG:   _value.j = locals->long_at  (_index);   break;
--- a/src/hotspot/share/prims/jvmtiImpl.hpp	Thu Nov 08 02:47:50 2018 +0100
+++ b/src/hotspot/share/prims/jvmtiImpl.hpp	Thu Nov 08 00:07:48 2018 -0800
@@ -382,7 +382,8 @@
 
   vframe* get_vframe();
   javaVFrame* get_java_vframe();
-  bool check_slot_type(javaVFrame* vf);
+  bool check_slot_type_lvt(javaVFrame* vf);
+  bool check_slot_type_no_lvt(javaVFrame* vf);
 
 public:
   // Constructor for non-object getter
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/GetLocalVariable/GetLocalVars.java	Thu Nov 08 00:07:48 2018 -0800
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+/*
+ * @test
+ * @bug 8080406
+ * @summary VM_GetOrSetLocal doesn't check local slot type against requested type
+ *
+ * @compile GetLocalVars.java
+ * @run main/othervm/native -Xcomp -agentlib:GetLocalVars GetLocalVars
+ */
+
+
+public class GetLocalVars {
+    private static final String agentLib = "GetLocalVars";
+
+    static native void testLocals(Thread thread);
+    static native int getStatus();
+
+    public static
+    void main(String[] args) throws Exception {
+        try {
+            System.loadLibrary(agentLib);
+        } catch (UnsatisfiedLinkError ex) {
+            System.err.println("Failed to load " + agentLib + " lib");
+            System.err.println("java.library.path: " + System.getProperty("java.library.path"));
+            throw ex;
+        }
+        run(args);
+        int status = getStatus();
+        if (status != 0) {
+            throw new RuntimeException("Test GetLocalVars failed with a bad status: " + status);
+        }
+    }
+
+    public static
+    void run(String argv[]) {
+        GetLocalVars testedObj = new GetLocalVars();
+        double pi = 3.14d;
+        byte sym = 'X';
+        int year = 2018;
+
+        staticMeth(sym, testedObj, pi, year);
+    }
+
+    public static synchronized
+    int staticMeth(byte byteArg, Object objArg, double dblArg, int intArg) {
+        testLocals(Thread.currentThread());
+        {
+            int intLoc = 9999;
+            intArg = intLoc;
+        }
+        return intArg;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/jvmti/GetLocalVariable/libGetLocalVars.cpp	Thu Nov 08 00:07:48 2018 -0800
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include "jvmti.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define STATUS_PASSED 0
+#define STATUS_FAILED 2
+#define TranslateError(err) "JVMTI error"
+
+static jint result = STATUS_PASSED;
+static jvmtiEnv *jvmti = NULL;
+
+#define DECL_TEST_FUNC(type, Type) \
+static void \
+test_##type(jthread thr, int depth, int slot, const char* exp_type) { \
+  j##type val; \
+  jvmtiError err = jvmti->GetLocal##Type(thr, depth, slot, &val); \
+  \
+  printf(" GetLocal%s: %s (%d)\n", #Type, TranslateError(err), err); \
+  if (err != JVMTI_ERROR_NONE) { \
+    printf(" FAIL: GetLocal%s failed to get value from a local %s\n", #Type, exp_type); \
+    result = STATUS_FAILED; \
+  } else { \
+    printf(" GetLocal%s got value from a local %s as expected\n", #Type, exp_type); \
+  } \
+}
+
+#define DECL_TEST_INV_SLOT_FUNC(type, Type) \
+static void \
+test_##type##_inv_slot(jthread thr, int depth, int slot, const char* exp_type) { \
+  j##type val; \
+  jvmtiError err = jvmti->GetLocal##Type(thr, depth, slot, &val); \
+  \
+  printf(" GetLocal%s: %s (%d)\n", #Type, TranslateError(err), err); \
+  if (err != JVMTI_ERROR_INVALID_SLOT) { \
+    printf(" FAIL: GetLocal%s failed to return JVMTI_ERROR_INVALID_SLOT for local %s\n", #Type, exp_type); \
+    result = STATUS_FAILED; \
+  } else { \
+    printf(" GetLocal%s returned JVMTI_ERROR_INVALID_SLOT for local %s as expected\n", #Type, exp_type); \
+  } \
+}
+
+#define DECL_TEST_TYPE_MISMATCH_FUNC(type, Type) \
+static void \
+test_##type##_type_mismatch(jthread thr, int depth, int slot, const char* exp_type) { \
+  j##type val; \
+  jvmtiError err = jvmti->GetLocal##Type(thr, depth, slot, &val); \
+  \
+  printf(" GetLocal%s: %s (%d)\n", #Type, TranslateError(err), err); \
+  if (err != JVMTI_ERROR_TYPE_MISMATCH) { \
+    printf(" FAIL: GetLocal%s failed to return JVMTI_ERROR_TYPE_MISMATCH for local %s\n", #Type, exp_type); \
+    result = STATUS_FAILED; \
+  } else { \
+    printf(" GetLocal%s returned JVMTI_ERROR_TYPE_MISMATCH for local %s as expected\n", #Type, exp_type); \
+  } \
+}
+
+DECL_TEST_FUNC(int, Int);
+DECL_TEST_FUNC(float, Float);
+DECL_TEST_FUNC(long, Long);
+DECL_TEST_FUNC(double, Double);
+DECL_TEST_FUNC(object, Object);
+
+DECL_TEST_INV_SLOT_FUNC(int, Int);
+DECL_TEST_INV_SLOT_FUNC(float, Float);
+DECL_TEST_INV_SLOT_FUNC(long, Long);
+DECL_TEST_INV_SLOT_FUNC(double, Double);
+DECL_TEST_INV_SLOT_FUNC(object, Object);
+
+DECL_TEST_TYPE_MISMATCH_FUNC(int, Int);
+DECL_TEST_TYPE_MISMATCH_FUNC(float, Float);
+DECL_TEST_TYPE_MISMATCH_FUNC(long, Long);
+DECL_TEST_TYPE_MISMATCH_FUNC(double, Double);
+DECL_TEST_TYPE_MISMATCH_FUNC(object, Object);
+
+static void
+test_local_byte(jthread thr, int depth, int slot) {
+  printf("\n test_local_byte: BEGIN\n\n");
+
+  test_int(thr, depth, slot, "byte");
+  test_long_inv_slot(thr, depth, slot, "byte");
+  test_float(thr, depth, slot, "byte");
+  test_double_inv_slot(thr, depth, slot, "byte");
+  test_object_type_mismatch(thr, depth, slot, "byte");
+
+  printf("\n test_local_byte: END\n\n");
+}
+
+static void
+test_local_object(jthread thr, int depth, int slot) {
+  printf("\n test_local_object: BEGIN\n\n");
+
+  test_int_type_mismatch(thr, depth, slot, "object");
+  test_long_type_mismatch(thr, depth, slot, "object");
+  test_float_type_mismatch(thr, depth, slot, "object");
+  test_double_type_mismatch(thr, depth, slot, "object");
+  test_object(thr, depth, slot, "object");
+
+  printf("\n test_local_object: END\n\n");
+}
+
+static void
+test_local_double(jthread thr, int depth, int slot) {
+  printf("\n test_local_double: BEGIN\n\n");
+
+  test_int(thr, depth, slot, "double");
+  test_long(thr, depth, slot, "double");
+  test_float(thr, depth, slot, "double");
+  test_double(thr, depth, slot, "double");
+  test_object_type_mismatch(thr, depth, slot, "double");
+
+  printf("\n test_local_double: END\n\n");
+}
+
+static void
+test_local_integer(jthread thr, int depth, int slot) {
+  printf("\n test_local_integer: BEGIN\n\n");
+
+  test_int(thr, depth, slot, "int");
+  test_long_inv_slot(thr, depth, slot, "int");
+  test_float(thr, depth, slot, "int");
+  test_double_inv_slot(thr, depth, slot, "int");
+  test_object_type_mismatch(thr, depth, slot, "double");
+
+  printf("\n test_local_integer: END\n\n");
+}
+
+static void
+test_local_invalid(jthread thr, int depth, int slot) {
+  printf("\n test_local_invalid: BEGIN\n\n");
+
+  test_int_inv_slot(thr, depth, slot, "invalid");
+  test_long_inv_slot(thr, depth, slot, "invalid");
+  test_float_inv_slot(thr, depth, slot, "invalid");
+  test_double_inv_slot(thr, depth, slot, "invalid");
+  test_object_inv_slot(thr, depth, slot, "invalid");
+
+  printf("\n test_local_invalid: END\n\n");
+}
+
+jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
+  jint res;
+  jvmtiError err;
+  static jvmtiCapabilities caps;
+
+  res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION_9);
+  if (res != JNI_OK || jvmti == NULL) {
+    printf("Wrong result of a valid call to GetEnv!\n");
+    return JNI_ERR;
+  }
+  caps.can_access_local_variables = 1;
+
+  err = jvmti->AddCapabilities(&caps);
+  if (err != JVMTI_ERROR_NONE) {
+    printf("AddCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err);
+    return JNI_ERR;
+  }
+  err = jvmti->GetCapabilities(&caps);
+  if (err != JVMTI_ERROR_NONE) {
+    printf("GetCapabilities: unexpected error: %s (%d)\n", TranslateError(err), err);
+    return JNI_ERR;
+  }
+  if (!caps.can_access_local_variables) {
+    printf("Warning: Access to local variables is not implemented\n");
+    return JNI_ERR;
+  }
+  return JNI_OK;
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
+  return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT jint JNICALL
+Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
+  return Agent_Initialize(jvm, options, reserved);
+}
+
+JNIEXPORT void JNICALL
+Java_GetLocalVars_testLocals(JNIEnv *env, jclass cls, jobject thread) {
+  static const char* METHOD_NAME = "staticMeth";
+  static const char* METHOD_SIGN = "(BLjava/lang/Object;DI)I";
+  static const int Depth = 1;
+  static const int ByteSlot = 0;
+  static const int ObjSlot = 1;
+  static const int DblSlot = 2;
+  static const int IntSlot = 4;
+  static const int InvalidSlot = 5;
+
+  jmethodID mid = NULL;
+
+  if (jvmti == NULL) {
+    printf("JVMTI client was not properly loaded!\n");
+    result = STATUS_FAILED;
+    return;
+  }
+
+  mid = env->GetStaticMethodID(cls, METHOD_NAME, METHOD_SIGN);
+  if (mid == NULL) {
+    printf("Cannot find Method ID for %s%s\n", METHOD_NAME, METHOD_SIGN);
+    result = STATUS_FAILED;
+    return;
+  }
+
+  test_local_byte(thread, Depth, ByteSlot);
+  test_local_object(thread, Depth, ObjSlot);
+  test_local_double(thread, Depth, DblSlot);
+  test_local_integer(thread, Depth, IntSlot);
+  test_local_invalid(thread, Depth, InvalidSlot);
+}
+
+JNIEXPORT jint JNICALL
+Java_GetLocalVars_getStatus(JNIEnv *env, jclass cls) {
+    return result;
+}
+
+#ifdef __cplusplus
+}
+#endif
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal003/getlocal003.cpp	Thu Nov 08 02:47:50 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal003/getlocal003.cpp	Thu Nov 08 00:07:48 2018 -0800
@@ -21,9 +21,6 @@
  * questions.
  */
 
-/*
- */
-
 #include <stdio.h>
 #include <string.h>
 #include "jvmti.h"
@@ -34,13 +31,12 @@
 extern "C" {
 
 
-#define PASSED 0
+#define STATUS_PASSED 0
 #define STATUS_FAILED 2
 
 static jvmtiEnv *jvmti = NULL;
-static jvmtiCapabilities caps;
 static jvmtiEventCallbacks callbacks;
-static jint result = PASSED;
+static jint result = STATUS_PASSED;
 static jboolean printdump = JNI_FALSE;
 static jmethodID mid = NULL;
 static jvmtiLocalVariableEntry *table = NULL;
@@ -54,69 +50,112 @@
   printf(", signature: %s\n", lvt_elem->signature);
 }
 
-void JNICALL MethodExit(jvmtiEnv *jvmti_env, JNIEnv *env,
-        jthread thr, jmethodID method,
-        jboolean was_poped_by_exception, jvalue return_value) {
+static void
+test_locals(jvmtiEnv *jvmti, jthread thr, jlocation location) {
     jvmtiError err;
-    jint i;
-    jmethodID frame_method;
-    jlocation location;
     jint intVal;
+    jlong longVal;
     jfloat floatVal;
     jdouble doubleVal;
     jobject obj;
+    jint i;
 
-    if (mid == method) {
+    for (i = 0; i < entryCount; i++) {
+        if (table[i].start_location > location ||
+            table[i].start_location + table[i].length < location) {
+            continue;  /* The local variable is not visible */
+        }
+        print_LocalVariableEntry(&table[i]);
+        char sig = table[i].signature[0];
 
-        err = jvmti_env->GetFrameLocation(thr, 0,
-                                             &frame_method, &location);
-        if (err != JVMTI_ERROR_NONE) {
-            printf("\t failure: %s (%d)\n", TranslateError(err), err);
+        if (sig == 'Z' || sig == 'B' || sig == 'C' || sig == 'S') {
+            sig = 'I'; // covered by GetLocalInt
+        }
+        err = jvmti->GetLocalInt(thr, 0, table[i].slot, &intVal);
+        printf(" GetLocalInt:     %s (%d)\n", TranslateError(err), err);
+        if (err != JVMTI_ERROR_NONE && sig == 'I') {
+            printf("FAIL: GetLocalInt failed to get value of int\n");
+            result = STATUS_FAILED;
+        } else if (err != JVMTI_ERROR_TYPE_MISMATCH && sig != 'I') {
+            printf("FAIL: GetLocalInt did not return JVMTI_ERROR_TYPE_MISMATCH for non-int\n");
             result = STATUS_FAILED;
-            return;
         }
-        if (frame_method != method) {
-            printf("\t failure: GetFrameLocation returned wrong jmethodID\n");
+
+        err = jvmti->GetLocalLong(thr, 0, table[i].slot, &longVal);
+        printf(" GetLocalLong:    %s (%d)\n", TranslateError(err), err);
+        if (err != JVMTI_ERROR_NONE && sig == 'J') {
+            printf("FAIL: GetLocalLong failed to get value of long\n");
+            result = STATUS_FAILED;
+        } else if (err != JVMTI_ERROR_TYPE_MISMATCH && sig != 'J') {
+            printf("FAIL: GetLocalLong did not return JVMTI_ERROR_TYPE_MISMATCH for non-long\n");
             result = STATUS_FAILED;
-            return;
+        }
+
+        err = jvmti->GetLocalFloat(thr, 0, table[i].slot, &floatVal);
+        printf(" GetLocalFloat:   %s (%d)\n", TranslateError(err), err);
+        if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'F') {
+            printf("FAIL: GetLocalFloat failed to get value of float\n");
+            result = STATUS_FAILED;
+        } else if (err != JVMTI_ERROR_TYPE_MISMATCH && table[i].signature[0] != 'F') {
+            printf("FAIL: GetLocalFloat did not return JVMTI_ERROR_TYPE_MISMATCH for non-float\n");
+            result = STATUS_FAILED;
         }
 
-        printf("\n MethodExit: BEGIN %d, Current frame bci: %" LL "d\n\n",
-                ++methodExitCnt, location);
-        for (i = 0; i < entryCount; i++) {
-            if (table[i].start_location > location ||
-                table[i].start_location + table[i].length < location) {
-                continue;  /* The local variable is not visible */
-            }
-            print_LocalVariableEntry(&table[i]);
+        err = jvmti->GetLocalDouble(thr, 0, table[i].slot, &doubleVal);
+        printf(" GetLocalDouble:  %s (%d)\n", TranslateError(err), err);
+        if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'D') {
+            printf("FAIL: GetLocalDouble failed to get value of double\n");
+            result = STATUS_FAILED;
+        } else if (err != JVMTI_ERROR_TYPE_MISMATCH && table[i].signature[0] != 'D') {
+            printf("FAIL: GetLocalDouble did not return JVMTI_ERROR_TYPE_MISMATCH for non-double\n");
+            result = STATUS_FAILED;
+        }
 
-            err = jvmti->GetLocalInt(thr, 0, table[i].slot, &intVal);
-            printf(" GetLocalInt:     %s (%d)\n", TranslateError(err), err);
-            if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'I') {
-                result = STATUS_FAILED;
-            }
+        err = jvmti->GetLocalObject(thr, 0, table[i].slot, &obj);
+        printf(" GetLocalObject:  %s (%d)\n", TranslateError(err), err);
+        if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'L') {
+            printf("FAIL: GetLocalObject failed to get value of object\n");
+            result = STATUS_FAILED;
+        } else if (err != JVMTI_ERROR_TYPE_MISMATCH && table[i].signature[0] != 'L') {
+            printf("FAIL: GetLocalObject did not return JVMTI_ERROR_TYPE_MISMATCH for non-object\n");
+            result = STATUS_FAILED;
+        }
+    }
+}
 
-            err = jvmti->GetLocalFloat(thr, 0, table[i].slot, &floatVal);
-            printf(" GetLocalFloat:   %s (%d)\n", TranslateError(err), err);
-            if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'F') {
-                result = STATUS_FAILED;
-            }
+static void JNICALL
+MethodExit(jvmtiEnv *jvmti_env,
+           JNIEnv *env,
+           jthread thr,
+           jmethodID method,
+           jboolean was_poped_by_exception,
+           jvalue return_value) {
+
+    jvmtiError err;
+    jlocation location;
+    jmethodID frame_method = NULL;
 
-            err = jvmti->GetLocalDouble(thr, 0, table[i].slot, &doubleVal);
-            printf(" GetLocalDouble:  %s (%d)\n", TranslateError(err), err);
-            if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'D') {
-                result = STATUS_FAILED;
-            }
+    if (mid != method) {
+        return;
+    }
+    err = jvmti->GetFrameLocation(thr, 0, &frame_method, &location);
+    if (err != JVMTI_ERROR_NONE) {
+        printf("\t failure: %s (%d)\n", TranslateError(err), err);
+        result = STATUS_FAILED;
+        return;
+    }
+    if (frame_method != method) {
+        printf("\t failure: GetFrameLocation returned wrong jmethodID\n");
+        result = STATUS_FAILED;
+        return;
+    }
 
-            err = jvmti->GetLocalObject(thr, 0, table[i].slot, &obj);
-            printf(" GetLocalObject:  %s (%d)\n", TranslateError(err), err);
-            if (err != JVMTI_ERROR_NONE && table[i].signature[0] == 'L') {
-                result = STATUS_FAILED;
-            }
-        }
-        printf("\n MethodExit: END %d\n\n", methodExitCnt);
-        fflush(stdout);
-    }
+    printf("\n MethodExit: BEGIN %d\n",  ++methodExitCnt);
+
+    test_locals(jvmti, thr, location);
+
+    printf("\n MethodExit: END %d\n\n", methodExitCnt);
+    fflush(stdout);
 }
 
 #ifdef STATIC_BUILD
@@ -133,6 +172,7 @@
 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
     jint res;
     jvmtiError err;
+    static jvmtiCapabilities caps;
 
     if (options != NULL && strcmp(options, "printdump") == 0) {
         printdump = JNI_TRUE;
@@ -167,18 +207,19 @@
 
     if (!caps.can_access_local_variables) {
         printf("Warning: Access to local variables is not implemented\n");
-    } else if (caps.can_generate_method_exit_events) {
-        callbacks.MethodExit = &MethodExit;
-        err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
-        if (err != JVMTI_ERROR_NONE) {
-            printf("(SetEventCallbacks) unexpected error: %s (%d)\n",
-                   TranslateError(err), err);
-            return JNI_ERR;
-        }
-    } else {
+        return JNI_ERR;
+    }
+    if (!caps.can_generate_method_exit_events) {
         printf("Warning: MethodExit event is not implemented\n");
+        return JNI_ERR;
     }
-
+    callbacks.MethodExit = &MethodExit;
+    err = jvmti->SetEventCallbacks(&callbacks, sizeof(callbacks));
+    if (err != JVMTI_ERROR_NONE) {
+        printf("(SetEventCallbacks) unexpected error: %s (%d)\n",
+               TranslateError(err), err);
+        return JNI_ERR;
+    }
     return JNI_OK;
 }
 
@@ -192,9 +233,6 @@
         return;
     }
 
-    if (!caps.can_access_local_variables ||
-        !caps.can_generate_method_exit_events) return;
-
     mid = env->GetStaticMethodID(cls, "staticMeth", "(I)I");
     if (mid == NULL) {
         printf("Cannot find Method ID for staticMeth\n");
@@ -204,14 +242,13 @@
 
     err = jvmti->GetLocalVariableTable(mid, &entryCount, &table);
     if (err != JVMTI_ERROR_NONE) {
-            printf("(GetLocalVariableTable) unexpected error: %s (%d)\n",
-                   TranslateError(err), err);
-            result = STATUS_FAILED;
-            return;
+        printf("(GetLocalVariableTable) unexpected error: %s (%d)\n",
+               TranslateError(err), err);
+        result = STATUS_FAILED;
+        return;
     }
 
-    err = jvmti->SetEventNotificationMode(JVMTI_ENABLE,
-        JVMTI_EVENT_METHOD_EXIT, NULL);
+    err = jvmti->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_METHOD_EXIT, NULL);
     if (err != JVMTI_ERROR_NONE) {
         printf("Failed to enable metod exit event: %s (%d)\n",
                TranslateError(err), err);
@@ -232,8 +269,11 @@
     int  overlap = 0;
 
     if (jvmti == NULL) {
+        printf("JVMTI client was not properly loaded!\n");
+        result = STATUS_FAILED;
         return;
     }
+    printf("\n checkLoc: START\n");
 
     mid = env->GetStaticMethodID(cls, "staticMeth", "(I)I");
     if (mid == NULL) {
@@ -255,20 +295,22 @@
 
         err = jvmti->GetLocalInt(thr, 1, table[i].slot, &locVar);
 
-        printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err);
         if (strcmp(table[i].name, "intArg") == 0) {
             if (err != JVMTI_ERROR_NONE) {
-               printf(" failure: JVMTI_ERROR_NONE is expected\n");
-               result = STATUS_FAILED;
+                printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err);
+                printf(" failure: JVMTI_ERROR_NONE is expected\n");
+                result = STATUS_FAILED;
             }
         }
         else if (strcmp(table[i].name, "pi") == 0) {
             if (err != JVMTI_ERROR_TYPE_MISMATCH) {
-               printf(" failure: JVMTI_ERROR_TYPE_MISMATCH is expected\n");
-               result = STATUS_FAILED;
+                printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err);
+                printf(" failure: JVMTI_ERROR_TYPE_MISMATCH is expected\n");
+                result = STATUS_FAILED;
             }
         } else {
             if (err != JVMTI_ERROR_INVALID_SLOT) {
+                printf(" GetLocalInt: %s (%d)\n", TranslateError(err), err);
                 printf(" failure: JVMTI_ERROR_INVALID_SLOT is expected\n");
                 result = STATUS_FAILED;
             }
@@ -290,7 +332,7 @@
                continue; /* Everything is Ok */
            }
 
-           printf(" failure: locations of vars with slot #2 are overlaped:\n");
+           printf(" failure: locations of vars with slot #2 are overlapped:\n");
            print_LocalVariableEntry(&table[i]);
            print_LocalVariableEntry(&table[j]);
            overlap++;
@@ -298,8 +340,9 @@
         }
     }
     if (!overlap) {
-        printf("\n Succes: locations of vars with slot #2 are NOT overlaped\n\n");
+        printf("\n Success: locations of vars with slot #2 are NOT overlapped\n");
     }
+    printf("\n checkLoc: END\n\n");
     fflush(stdout);
 }
 
--- a/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal004/getlocal004.cpp	Thu Nov 08 02:47:50 2018 +0100
+++ b/test/hotspot/jtreg/vmTestbase/nsk/jvmti/unit/GetLocalVariable/getlocal004/getlocal004.cpp	Thu Nov 08 00:07:48 2018 -0800
@@ -21,9 +21,6 @@
  * questions.
  */
 
-/*
- */
-
 #include <stdio.h>
 #include <string.h>
 #include "jvmti.h"
@@ -34,14 +31,12 @@
 extern "C" {
 
 
-#define PASSED 0
+#define STATUS_PASSED 0
 #define STATUS_FAILED 2
 
 static jvmtiEnv *jvmti = NULL;
-static jvmtiCapabilities caps;
-static jint result = PASSED;
+static jint result = STATUS_PASSED;
 static jboolean printdump = JNI_FALSE;
-static jmethodID mid = NULL;
 
 void print_LocalVariableEntry(jvmtiLocalVariableEntry *lvt_elem) {
   printf("\n Var name: %s, slot: %d", lvt_elem->name, lvt_elem->slot);
@@ -64,6 +59,7 @@
 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
     jint res;
     jvmtiError err;
+    static jvmtiCapabilities caps;
 
     if (options != NULL && strcmp(options, "printdump") == 0) {
         printdump = JNI_TRUE;
@@ -98,29 +94,31 @@
 
     if (!caps.can_access_local_variables) {
         printf("Warning: Access to local variables is not implemented\n");
+        return JNI_ERR;
     }
-
+    if (!caps.can_access_local_variables) {
+        printf("Warning: Access to local variables is not implemented\n");
+        return JNI_ERR;
+    }
     return JNI_OK;
 }
 
 JNIEXPORT void JNICALL
 Java_nsk_jvmti_unit_GetLocalVariable_getlocal004_getMeth(JNIEnv *env, jclass cls) {
+    jmethodID mid = NULL;
+
     if (jvmti == NULL) {
         printf("JVMTI client was not properly loaded!\n");
         result = STATUS_FAILED;
         return;
     }
 
-    if (!caps.can_access_local_variables ||
-        !caps.can_generate_method_exit_events) return;
-
     mid = env->GetStaticMethodID(cls, "staticMeth", "(I)I");
     if (mid == NULL) {
         printf("Cannot find Method ID for staticMeth\n");
         result = STATUS_FAILED;
         return;
     }
-
     fflush(stdout);
 }