Check for unattached threads in JVMTI functions
Calling the JVMTI functions with an unattached thread is required to
return JVMTI_ERROR_UNATTACHED_THREAD.
Test: ./test.py --host -j40
Bug: 36576873
Change-Id: I312b4e0a5e5fb66961f6efcc36d9480626c3461f
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 5401e5c..735b4c0 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -79,20 +79,26 @@
class JvmtiFunctions {
private:
- static bool IsValidEnv(jvmtiEnv* env) {
- return env != nullptr;
+ static jvmtiError getEnvironmentError(jvmtiEnv* env) {
+ if (env == nullptr) {
+ return ERR(INVALID_ENVIRONMENT);
+ } else if (art::Thread::Current() == nullptr) {
+ return ERR(UNATTACHED_THREAD);
+ } else {
+ return OK;
+ }
}
-#define ENSURE_VALID_ENV(env) \
- do { \
- if (!IsValidEnv(env)) { \
- return ERR(INVALID_ENVIRONMENT); \
- } \
+#define ENSURE_VALID_ENV(env) \
+ do { \
+ jvmtiError ensure_valid_env_ ## __LINE__ = getEnvironmentError(env); \
+ if (ensure_valid_env_ ## __LINE__ != OK) { \
+ return ensure_valid_env_ ## __LINE__ ; \
+ } \
} while (false)
#define ENSURE_HAS_CAP(env, cap) \
do { \
- ENSURE_VALID_ENV(env); \
if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.cap != 1) { \
return ERR(MUST_POSSESS_CAPABILITY); \
} \
@@ -121,18 +127,22 @@
}
static jvmtiError GetThreadState(jvmtiEnv* env, jthread thread, jint* thread_state_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::GetThreadState(env, thread, thread_state_ptr);
}
static jvmtiError GetCurrentThread(jvmtiEnv* env, jthread* thread_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::GetCurrentThread(env, thread_ptr);
}
static jvmtiError GetAllThreads(jvmtiEnv* env, jint* threads_count_ptr, jthread** threads_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::GetAllThreads(env, threads_count_ptr, threads_ptr);
}
static jvmtiError SuspendThread(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_suspend);
return ERR(NOT_IMPLEMENTED);
}
@@ -141,11 +151,13 @@
jint request_count ATTRIBUTE_UNUSED,
const jthread* request_list ATTRIBUTE_UNUSED,
jvmtiError* results ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_suspend);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError ResumeThread(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_suspend);
return ERR(NOT_IMPLEMENTED);
}
@@ -154,6 +166,7 @@
jint request_count ATTRIBUTE_UNUSED,
const jthread* request_list ATTRIBUTE_UNUSED,
jvmtiError* results ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_suspend);
return ERR(NOT_IMPLEMENTED);
}
@@ -161,16 +174,19 @@
static jvmtiError StopThread(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jobject exception ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_signal_thread);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError InterruptThread(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_signal_thread);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetThreadInfo(jvmtiEnv* env, jthread thread, jvmtiThreadInfo* info_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::GetThreadInfo(env, thread, info_ptr);
}
@@ -178,6 +194,7 @@
jthread thread ATTRIBUTE_UNUSED,
jint* owned_monitor_count_ptr ATTRIBUTE_UNUSED,
jobject** owned_monitors_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_owned_monitor_info);
return ERR(NOT_IMPLEMENTED);
}
@@ -187,6 +204,7 @@
jthread thread ATTRIBUTE_UNUSED,
jint* monitor_info_count_ptr ATTRIBUTE_UNUSED,
jvmtiMonitorStackDepthInfo** monitor_info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_owned_monitor_stack_depth_info);
return ERR(NOT_IMPLEMENTED);
}
@@ -194,6 +212,7 @@
static jvmtiError GetCurrentContendedMonitor(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jobject* monitor_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_current_contended_monitor);
return ERR(NOT_IMPLEMENTED);
}
@@ -203,26 +222,31 @@
jvmtiStartFunction proc,
const void* arg,
jint priority) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::RunAgentThread(env, thread, proc, arg, priority);
}
static jvmtiError SetThreadLocalStorage(jvmtiEnv* env, jthread thread, const void* data) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::SetThreadLocalStorage(env, thread, data);
}
static jvmtiError GetThreadLocalStorage(jvmtiEnv* env, jthread thread, void** data_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadUtil::GetThreadLocalStorage(env, thread, data_ptr);
}
static jvmtiError GetTopThreadGroups(jvmtiEnv* env,
jint* group_count_ptr,
jthreadGroup** groups_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadGroupUtil::GetTopThreadGroups(env, group_count_ptr, groups_ptr);
}
static jvmtiError GetThreadGroupInfo(jvmtiEnv* env,
jthreadGroup group,
jvmtiThreadGroupInfo* info_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadGroupUtil::GetThreadGroupInfo(env, group, info_ptr);
}
@@ -232,6 +256,7 @@
jthread** threads_ptr,
jint* group_count_ptr,
jthreadGroup** groups_ptr) {
+ ENSURE_VALID_ENV(env);
return ThreadGroupUtil::GetThreadGroupChildren(env,
group,
thread_count_ptr,
@@ -246,6 +271,7 @@
jint max_frame_count,
jvmtiFrameInfo* frame_buffer,
jint* count_ptr) {
+ ENSURE_VALID_ENV(env);
return StackUtil::GetStackTrace(env,
thread,
start_depth,
@@ -258,6 +284,7 @@
jint max_frame_count,
jvmtiStackInfo** stack_info_ptr,
jint* thread_count_ptr) {
+ ENSURE_VALID_ENV(env);
return StackUtil::GetAllStackTraces(env, max_frame_count, stack_info_ptr, thread_count_ptr);
}
@@ -266,6 +293,7 @@
const jthread* thread_list,
jint max_frame_count,
jvmtiStackInfo** stack_info_ptr) {
+ ENSURE_VALID_ENV(env);
return StackUtil::GetThreadListStackTraces(env,
thread_count,
thread_list,
@@ -274,10 +302,12 @@
}
static jvmtiError GetFrameCount(jvmtiEnv* env, jthread thread, jint* count_ptr) {
+ ENSURE_VALID_ENV(env);
return StackUtil::GetFrameCount(env, thread, count_ptr);
}
static jvmtiError PopFrame(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_pop_frame);
return ERR(NOT_IMPLEMENTED);
}
@@ -287,12 +317,14 @@
jint depth,
jmethodID* method_ptr,
jlocation* location_ptr) {
+ ENSURE_VALID_ENV(env);
return StackUtil::GetFrameLocation(env, thread, depth, method_ptr, location_ptr);
}
static jvmtiError NotifyFramePop(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jint depth ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_frame_pop_events);
return ERR(NOT_IMPLEMENTED);
}
@@ -300,6 +332,7 @@
static jvmtiError ForceEarlyReturnObject(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jobject value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_force_early_return);
return ERR(NOT_IMPLEMENTED);
}
@@ -307,6 +340,7 @@
static jvmtiError ForceEarlyReturnInt(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jint value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_force_early_return);
return ERR(NOT_IMPLEMENTED);
}
@@ -314,6 +348,7 @@
static jvmtiError ForceEarlyReturnLong(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jlong value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_force_early_return);
return ERR(NOT_IMPLEMENTED);
}
@@ -321,6 +356,7 @@
static jvmtiError ForceEarlyReturnFloat(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jfloat value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_force_early_return);
return ERR(NOT_IMPLEMENTED);
}
@@ -328,11 +364,13 @@
static jvmtiError ForceEarlyReturnDouble(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jdouble value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_force_early_return);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError ForceEarlyReturnVoid(jvmtiEnv* env, jthread thread ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_force_early_return);
return ERR(NOT_IMPLEMENTED);
}
@@ -343,6 +381,7 @@
jobject initial_object,
const jvmtiHeapCallbacks* callbacks,
const void* user_data) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
return heap_util.FollowReferences(env,
@@ -358,12 +397,14 @@
jclass klass,
const jvmtiHeapCallbacks* callbacks,
const void* user_data) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
return heap_util.IterateThroughHeap(env, heap_filter, klass, callbacks, user_data);
}
static jvmtiError GetTag(jvmtiEnv* env, jobject object, jlong* tag_ptr) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
JNIEnv* jni_env = GetJniEnv(env);
@@ -381,6 +422,7 @@
}
static jvmtiError SetTag(jvmtiEnv* env, jobject object, jlong tag) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
if (object == nullptr) {
@@ -405,6 +447,7 @@
jint* count_ptr,
jobject** object_result_ptr,
jlong** tag_result_ptr) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
JNIEnv* jni_env = GetJniEnv(env);
@@ -422,6 +465,7 @@
}
static jvmtiError ForceGarbageCollection(jvmtiEnv* env) {
+ ENSURE_VALID_ENV(env);
return HeapUtil::ForceGarbageCollection(env);
}
@@ -430,6 +474,7 @@
jobject object ATTRIBUTE_UNUSED,
jvmtiObjectReferenceCallback object_reference_callback ATTRIBUTE_UNUSED,
const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
return ERR(NOT_IMPLEMENTED);
}
@@ -440,6 +485,7 @@
jvmtiStackReferenceCallback stack_ref_callback ATTRIBUTE_UNUSED,
jvmtiObjectReferenceCallback object_ref_callback ATTRIBUTE_UNUSED,
const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
return ERR(NOT_IMPLEMENTED);
}
@@ -448,6 +494,7 @@
jvmtiHeapObjectFilter object_filter ATTRIBUTE_UNUSED,
jvmtiHeapObjectCallback heap_object_callback ATTRIBUTE_UNUSED,
const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
return ERR(NOT_IMPLEMENTED);
}
@@ -458,6 +505,7 @@
jvmtiHeapObjectFilter object_filter ATTRIBUTE_UNUSED,
jvmtiHeapObjectCallback heap_object_callback ATTRIBUTE_UNUSED,
const void* user_data ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_tag_objects);
return ERR(NOT_IMPLEMENTED);
}
@@ -467,6 +515,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jobject* value_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -475,6 +524,7 @@
jthread thread ATTRIBUTE_UNUSED,
jint depth ATTRIBUTE_UNUSED,
jobject* value_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -484,6 +534,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jint* value_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -493,6 +544,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jlong* value_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -502,6 +554,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jfloat* value_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -511,6 +564,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jdouble* value_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -520,6 +574,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jobject value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -529,6 +584,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jint value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -538,6 +594,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jlong value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -547,6 +604,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jfloat value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -556,6 +614,7 @@
jint depth ATTRIBUTE_UNUSED,
jint slot ATTRIBUTE_UNUSED,
jdouble value ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -563,6 +622,7 @@
static jvmtiError SetBreakpoint(jvmtiEnv* env,
jmethodID method ATTRIBUTE_UNUSED,
jlocation location ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_breakpoint_events);
return ERR(NOT_IMPLEMENTED);
}
@@ -570,6 +630,7 @@
static jvmtiError ClearBreakpoint(jvmtiEnv* env,
jmethodID method ATTRIBUTE_UNUSED,
jlocation location ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_breakpoint_events);
return ERR(NOT_IMPLEMENTED);
}
@@ -577,6 +638,7 @@
static jvmtiError SetFieldAccessWatch(jvmtiEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jfieldID field ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_field_access_events);
return ERR(NOT_IMPLEMENTED);
}
@@ -584,6 +646,7 @@
static jvmtiError ClearFieldAccessWatch(jvmtiEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jfieldID field ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_field_access_events);
return ERR(NOT_IMPLEMENTED);
}
@@ -591,6 +654,7 @@
static jvmtiError SetFieldModificationWatch(jvmtiEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jfieldID field ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_field_modification_events);
return ERR(NOT_IMPLEMENTED);
}
@@ -598,11 +662,13 @@
static jvmtiError ClearFieldModificationWatch(jvmtiEnv* env,
jclass klass ATTRIBUTE_UNUSED,
jfieldID field ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_generate_field_modification_events);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetLoadedClasses(jvmtiEnv* env, jint* class_count_ptr, jclass** classes_ptr) {
+ ENSURE_VALID_ENV(env);
HeapUtil heap_util(ArtJvmTiEnv::AsArtJvmTiEnv(env)->object_tag_table.get());
return heap_util.GetLoadedClasses(env, class_count_ptr, classes_ptr);
}
@@ -611,6 +677,7 @@
jobject initiating_loader,
jint* class_count_ptr,
jclass** classes_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassLoaderClasses(env, initiating_loader, class_count_ptr, classes_ptr);
}
@@ -618,21 +685,25 @@
jclass klass,
char** signature_ptr,
char** generic_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassSignature(env, klass, signature_ptr, generic_ptr);
}
static jvmtiError GetClassStatus(jvmtiEnv* env, jclass klass, jint* status_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassStatus(env, klass, status_ptr);
}
static jvmtiError GetSourceFileName(jvmtiEnv* env,
jclass klass ATTRIBUTE_UNUSED,
char** source_name_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_source_file_name);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetClassModifiers(jvmtiEnv* env, jclass klass, jint* modifiers_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassModifiers(env, klass, modifiers_ptr);
}
@@ -640,6 +711,7 @@
jclass klass,
jint* method_count_ptr,
jmethodID** methods_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassMethods(env, klass, method_count_ptr, methods_ptr);
}
@@ -647,6 +719,7 @@
jclass klass,
jint* field_count_ptr,
jfieldID** fields_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassFields(env, klass, field_count_ptr, fields_ptr);
}
@@ -654,6 +727,7 @@
jclass klass,
jint* interface_count_ptr,
jclass** interfaces_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetImplementedInterfaces(env, klass, interface_count_ptr, interfaces_ptr);
}
@@ -661,6 +735,7 @@
jclass klass,
jint* minor_version_ptr,
jint* major_version_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassVersionNumbers(env, klass, minor_version_ptr, major_version_ptr);
}
@@ -669,38 +744,45 @@
jint* constant_pool_count_ptr ATTRIBUTE_UNUSED,
jint* constant_pool_byte_count_ptr ATTRIBUTE_UNUSED,
unsigned char** constant_pool_bytes_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_constant_pool);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError IsInterface(jvmtiEnv* env, jclass klass, jboolean* is_interface_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::IsInterface(env, klass, is_interface_ptr);
}
static jvmtiError IsArrayClass(jvmtiEnv* env,
jclass klass,
jboolean* is_array_class_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::IsArrayClass(env, klass, is_array_class_ptr);
}
static jvmtiError IsModifiableClass(jvmtiEnv* env,
jclass klass,
jboolean* is_modifiable_class_ptr) {
+ ENSURE_VALID_ENV(env);
return Redefiner::IsModifiableClass(env, klass, is_modifiable_class_ptr);
}
static jvmtiError GetClassLoader(jvmtiEnv* env, jclass klass, jobject* classloader_ptr) {
+ ENSURE_VALID_ENV(env);
return ClassUtil::GetClassLoader(env, klass, classloader_ptr);
}
static jvmtiError GetSourceDebugExtension(jvmtiEnv* env,
jclass klass ATTRIBUTE_UNUSED,
char** source_debug_extension_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_source_debug_extension);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError RetransformClasses(jvmtiEnv* env, jint class_count, const jclass* classes) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_retransform_classes);
std::string error_msg;
jvmtiError res = Transformer::RetransformClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
@@ -719,6 +801,7 @@
static jvmtiError RedefineClasses(jvmtiEnv* env,
jint class_count,
const jvmtiClassDefinition* class_definitions) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_redefine_classes);
std::string error_msg;
jvmtiError res = Redefiner::RedefineClasses(ArtJvmTiEnv::AsArtJvmTiEnv(env),
@@ -735,16 +818,19 @@
}
static jvmtiError GetObjectSize(jvmtiEnv* env, jobject object, jlong* size_ptr) {
+ ENSURE_VALID_ENV(env);
return ObjectUtil::GetObjectSize(env, object, size_ptr);
}
static jvmtiError GetObjectHashCode(jvmtiEnv* env, jobject object, jint* hash_code_ptr) {
+ ENSURE_VALID_ENV(env);
return ObjectUtil::GetObjectHashCode(env, object, hash_code_ptr);
}
static jvmtiError GetObjectMonitorUsage(jvmtiEnv* env,
jobject object ATTRIBUTE_UNUSED,
jvmtiMonitorUsage* info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_monitor_info);
return ERR(NOT_IMPLEMENTED);
}
@@ -755,6 +841,7 @@
char** name_ptr,
char** signature_ptr,
char** generic_ptr) {
+ ENSURE_VALID_ENV(env);
return FieldUtil::GetFieldName(env, klass, field, name_ptr, signature_ptr, generic_ptr);
}
@@ -762,6 +849,7 @@
jclass klass,
jfieldID field,
jclass* declaring_class_ptr) {
+ ENSURE_VALID_ENV(env);
return FieldUtil::GetFieldDeclaringClass(env, klass, field, declaring_class_ptr);
}
@@ -769,6 +857,7 @@
jclass klass,
jfieldID field,
jint* modifiers_ptr) {
+ ENSURE_VALID_ENV(env);
return FieldUtil::GetFieldModifiers(env, klass, field, modifiers_ptr);
}
@@ -776,6 +865,7 @@
jclass klass,
jfieldID field,
jboolean* is_synthetic_ptr) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_synthetic_attribute);
return FieldUtil::IsFieldSynthetic(env, klass, field, is_synthetic_ptr);
}
@@ -785,30 +875,35 @@
char** name_ptr,
char** signature_ptr,
char** generic_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::GetMethodName(env, method, name_ptr, signature_ptr, generic_ptr);
}
static jvmtiError GetMethodDeclaringClass(jvmtiEnv* env,
jmethodID method,
jclass* declaring_class_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::GetMethodDeclaringClass(env, method, declaring_class_ptr);
}
static jvmtiError GetMethodModifiers(jvmtiEnv* env,
jmethodID method,
jint* modifiers_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::GetMethodModifiers(env, method, modifiers_ptr);
}
static jvmtiError GetMaxLocals(jvmtiEnv* env,
jmethodID method,
jint* max_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::GetMaxLocals(env, method, max_ptr);
}
static jvmtiError GetArgumentsSize(jvmtiEnv* env,
jmethodID method,
jint* size_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::GetArgumentsSize(env, method, size_ptr);
}
@@ -816,6 +911,7 @@
jmethodID method,
jint* entry_count_ptr,
jvmtiLineNumberEntry** table_ptr) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_line_numbers);
return MethodUtil::GetLineNumberTable(env, method, entry_count_ptr, table_ptr);
}
@@ -824,6 +920,7 @@
jmethodID method,
jlocation* start_location_ptr,
jlocation* end_location_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::GetMethodLocation(env, method, start_location_ptr, end_location_ptr);
}
@@ -831,6 +928,7 @@
jmethodID method ATTRIBUTE_UNUSED,
jint* entry_count_ptr ATTRIBUTE_UNUSED,
jvmtiLocalVariableEntry** table_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_access_local_variables);
return ERR(NOT_IMPLEMENTED);
}
@@ -839,24 +937,29 @@
jmethodID method ATTRIBUTE_UNUSED,
jint* bytecode_count_ptr ATTRIBUTE_UNUSED,
unsigned char** bytecodes_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_bytecodes);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError IsMethodNative(jvmtiEnv* env, jmethodID method, jboolean* is_native_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::IsMethodNative(env, method, is_native_ptr);
}
static jvmtiError IsMethodSynthetic(jvmtiEnv* env, jmethodID method, jboolean* is_synthetic_ptr) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_synthetic_attribute);
return MethodUtil::IsMethodSynthetic(env, method, is_synthetic_ptr);
}
static jvmtiError IsMethodObsolete(jvmtiEnv* env, jmethodID method, jboolean* is_obsolete_ptr) {
+ ENSURE_VALID_ENV(env);
return MethodUtil::IsMethodObsolete(env, method, is_obsolete_ptr);
}
static jvmtiError SetNativeMethodPrefix(jvmtiEnv* env, const char* prefix ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_set_native_method_prefix);
return ERR(NOT_IMPLEMENTED);
}
@@ -864,43 +967,53 @@
static jvmtiError SetNativeMethodPrefixes(jvmtiEnv* env,
jint prefix_count ATTRIBUTE_UNUSED,
char** prefixes ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_set_native_method_prefix);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError CreateRawMonitor(jvmtiEnv* env, const char* name, jrawMonitorID* monitor_ptr) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::CreateRawMonitor(env, name, monitor_ptr);
}
static jvmtiError DestroyRawMonitor(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::DestroyRawMonitor(env, monitor);
}
static jvmtiError RawMonitorEnter(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::RawMonitorEnter(env, monitor);
}
static jvmtiError RawMonitorExit(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::RawMonitorExit(env, monitor);
}
static jvmtiError RawMonitorWait(jvmtiEnv* env, jrawMonitorID monitor, jlong millis) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::RawMonitorWait(env, monitor, millis);
}
static jvmtiError RawMonitorNotify(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::RawMonitorNotify(env, monitor);
}
static jvmtiError RawMonitorNotifyAll(jvmtiEnv* env, jrawMonitorID monitor) {
+ ENSURE_VALID_ENV(env);
return MonitorUtil::RawMonitorNotifyAll(env, monitor);
}
static jvmtiError SetJNIFunctionTable(jvmtiEnv* env, const jniNativeInterface* function_table) {
+ ENSURE_VALID_ENV(env);
return JNIUtil::SetJNIFunctionTable(env, function_table);
}
static jvmtiError GetJNIFunctionTable(jvmtiEnv* env, jniNativeInterface** function_table) {
+ ENSURE_VALID_ENV(env);
return JNIUtil::GetJNIFunctionTable(env, function_table);
}
@@ -955,14 +1068,16 @@
return gEventHandler.SetEvent(art_env, art_thread, GetArtJvmtiEvent(art_env, event_type), mode);
}
- static jvmtiError GenerateEvents(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ static jvmtiError GenerateEvents(jvmtiEnv* env,
jvmtiEvent event_type ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
return OK;
}
- static jvmtiError GetExtensionFunctions(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ static jvmtiError GetExtensionFunctions(jvmtiEnv* env,
jint* extension_count_ptr,
jvmtiExtensionFunctionInfo** extensions) {
+ ENSURE_VALID_ENV(env);
// We do not have any extension functions.
*extension_count_ptr = 0;
*extensions = nullptr;
@@ -970,9 +1085,10 @@
return ERR(NONE);
}
- static jvmtiError GetExtensionEvents(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ static jvmtiError GetExtensionEvents(jvmtiEnv* env,
jint* extension_count_ptr,
jvmtiExtensionEventInfo** extensions) {
+ ENSURE_VALID_ENV(env);
// We do not have any extension events.
*extension_count_ptr = 0;
*extensions = nullptr;
@@ -980,9 +1096,10 @@
return ERR(NONE);
}
- static jvmtiError SetExtensionEventCallback(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ static jvmtiError SetExtensionEventCallback(jvmtiEnv* env,
jint extension_event_index ATTRIBUTE_UNUSED,
jvmtiExtensionEvent callback ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
// We do not have any extension events, so any call is illegal.
return ERR(ILLEGAL_ARGUMENT);
}
@@ -1141,17 +1258,20 @@
static jvmtiError GetCurrentThreadCpuTimerInfo(jvmtiEnv* env,
jvmtiTimerInfo* info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_current_thread_cpu_time);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetCurrentThreadCpuTime(jvmtiEnv* env, jlong* nanos_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_current_thread_cpu_time);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetThreadCpuTimerInfo(jvmtiEnv* env,
jvmtiTimerInfo* info_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_thread_cpu_time);
return ERR(NOT_IMPLEMENTED);
}
@@ -1159,43 +1279,53 @@
static jvmtiError GetThreadCpuTime(jvmtiEnv* env,
jthread thread ATTRIBUTE_UNUSED,
jlong* nanos_ptr ATTRIBUTE_UNUSED) {
+ ENSURE_VALID_ENV(env);
ENSURE_HAS_CAP(env, can_get_thread_cpu_time);
return ERR(NOT_IMPLEMENTED);
}
static jvmtiError GetTimerInfo(jvmtiEnv* env, jvmtiTimerInfo* info_ptr) {
+ ENSURE_VALID_ENV(env);
return TimerUtil::GetTimerInfo(env, info_ptr);
}
static jvmtiError GetTime(jvmtiEnv* env, jlong* nanos_ptr) {
+ ENSURE_VALID_ENV(env);
return TimerUtil::GetTime(env, nanos_ptr);
}
static jvmtiError GetAvailableProcessors(jvmtiEnv* env, jint* processor_count_ptr) {
+ ENSURE_VALID_ENV(env);
return TimerUtil::GetAvailableProcessors(env, processor_count_ptr);
}
static jvmtiError AddToBootstrapClassLoaderSearch(jvmtiEnv* env, const char* segment) {
+ ENSURE_VALID_ENV(env);
return SearchUtil::AddToBootstrapClassLoaderSearch(env, segment);
}
static jvmtiError AddToSystemClassLoaderSearch(jvmtiEnv* env, const char* segment) {
+ ENSURE_VALID_ENV(env);
return SearchUtil::AddToSystemClassLoaderSearch(env, segment);
}
static jvmtiError GetSystemProperties(jvmtiEnv* env, jint* count_ptr, char*** property_ptr) {
+ ENSURE_VALID_ENV(env);
return PropertiesUtil::GetSystemProperties(env, count_ptr, property_ptr);
}
static jvmtiError GetSystemProperty(jvmtiEnv* env, const char* property, char** value_ptr) {
+ ENSURE_VALID_ENV(env);
return PropertiesUtil::GetSystemProperty(env, property, value_ptr);
}
static jvmtiError SetSystemProperty(jvmtiEnv* env, const char* property, const char* value) {
+ ENSURE_VALID_ENV(env);
return PropertiesUtil::SetSystemProperty(env, property, value);
}
static jvmtiError GetPhase(jvmtiEnv* env, jvmtiPhase* phase_ptr) {
+ ENSURE_VALID_ENV(env);
return PhaseUtil::GetPhase(env, phase_ptr);
}
@@ -1303,9 +1433,10 @@
}
}
- static jvmtiError SetVerboseFlag(jvmtiEnv* env ATTRIBUTE_UNUSED,
+ static jvmtiError SetVerboseFlag(jvmtiEnv* env,
jvmtiVerboseFlag flag,
jboolean value) {
+ ENSURE_VALID_ENV(env);
if (flag == jvmtiVerboseFlag::JVMTI_VERBOSE_OTHER) {
// OTHER is special, as it's 0, so can't do a bit check.
bool val = (value == JNI_TRUE) ? true : false;
@@ -1359,8 +1490,8 @@
return ERR(NONE);
}
- static jvmtiError GetJLocationFormat(jvmtiEnv* env ATTRIBUTE_UNUSED,
- jvmtiJlocationFormat* format_ptr) {
+ static jvmtiError GetJLocationFormat(jvmtiEnv* env, jvmtiJlocationFormat* format_ptr) {
+ ENSURE_VALID_ENV(env);
// Report BCI as jlocation format. We report dex bytecode indices.
if (format_ptr == nullptr) {
return ERR(NULL_POINTER);
diff --git a/test/901-hello-ti-agent/basics.cc b/test/901-hello-ti-agent/basics.cc
index 9166277..cbd7686 100644
--- a/test/901-hello-ti-agent/basics.cc
+++ b/test/901-hello-ti-agent/basics.cc
@@ -16,6 +16,8 @@
#include "901-hello-ti-agent/basics.h"
+#include <thread>
+
#include <jni.h>
#include <stdio.h>
#include <string.h>
@@ -159,5 +161,19 @@
return (current_phase == JVMTI_PHASE_LIVE) ? JNI_TRUE : JNI_FALSE;
}
+static void CallJvmtiFunction(jvmtiEnv* env, jclass klass, jvmtiError* err) {
+ jint n;
+ jmethodID* methods = nullptr;
+ *err = env->GetClassMethods(klass, &n, &methods);
+}
+
+extern "C" JNIEXPORT jboolean JNICALL Java_Main_checkUnattached(
+ JNIEnv* env ATTRIBUTE_UNUSED, jclass Main_klass) {
+ jvmtiError res = JVMTI_ERROR_NONE;
+ std::thread t1(CallJvmtiFunction, jvmti_env, Main_klass, &res);
+ t1.join();
+ return res == JVMTI_ERROR_UNATTACHED_THREAD;
+}
+
} // namespace Test901HelloTi
} // namespace art
diff --git a/test/901-hello-ti-agent/expected.txt b/test/901-hello-ti-agent/expected.txt
index c4b24cb..eb5b6a2 100644
--- a/test/901-hello-ti-agent/expected.txt
+++ b/test/901-hello-ti-agent/expected.txt
@@ -3,6 +3,7 @@
VMInit
Hello, world!
Agent in live phase.
+Received expected error for unattached JVMTI calls
0
1
2
diff --git a/test/901-hello-ti-agent/src/Main.java b/test/901-hello-ti-agent/src/Main.java
index 4d62ed3..556e05b 100644
--- a/test/901-hello-ti-agent/src/Main.java
+++ b/test/901-hello-ti-agent/src/Main.java
@@ -21,6 +21,9 @@
if (checkLivePhase()) {
System.out.println("Agent in live phase.");
}
+ if (checkUnattached()) {
+ System.out.println("Received expected error for unattached JVMTI calls");
+ }
set(0); // OTHER
set(1); // GC
@@ -41,4 +44,5 @@
private static native boolean checkLivePhase();
private static native void setVerboseFlag(int flag, boolean value);
+ private static native boolean checkUnattached();
}