-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathjthreadmagic.c
75 lines (58 loc) · 2.7 KB
/
jthreadmagic.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <jni.h>
#include <jvmti.h>
jvmtiEnv *tiEnv = NULL;
jclass exceptionClass = NULL;
const jvmtiCapabilities neededCapabilities = {
.can_signal_thread = 1
};
#define ASSERT_FOR_LOAD(condition, reason) \
if(!(condition)){ \
fprintf(stderr, "JThreadMagic: failed to load -- " reason "!"); \
return JNI_ERR; \
}
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){
// Since JDK 1.2, only one JavaVM can be present per process, so it should be safe to fetch JVMTI env here
// and save it until this library is unloaded. It *should* also be safe to store the ThreadDeath class and constructor.
JNIEnv *env;
ASSERT_FOR_LOAD((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2) == JNI_OK, "cannot get JNI env");
ASSERT_FOR_LOAD((*vm)->GetEnv(vm, (void **)&tiEnv, JVMTI_VERSION_1_2) == JNI_OK, "cannot get JVMTI env");
ASSERT_FOR_LOAD((*tiEnv)->AddCapabilities(tiEnv, &neededCapabilities) == JVMTI_ERROR_NONE, "cannot add required JVMTI capabilities");
jclass localExceptionClass = (*env)->FindClass(env, "java/lang/Exception");
ASSERT_FOR_LOAD(localExceptionClass, "cannot find Exception class");
exceptionClass = (*env)->NewGlobalRef(env, localExceptionClass);
ASSERT_FOR_LOAD(exceptionClass, "cannot allocate global reference for Exception class");
return JNI_VERSION_1_2;
}
JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved){
if(tiEnv)
(*tiEnv)->DisposeEnvironment(tiEnv);
if(exceptionClass){
JNIEnv *env;
if((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2) == JNI_OK)
(*env)->DeleteGlobalRef(env, exceptionClass);
}
tiEnv = NULL;
exceptionClass = NULL;
}
JNIEXPORT void JNICALL Java_rip_mem_jthreadmagic_JThreadMagic_stopThread0(JNIEnv *env, jclass clazz, jobject threadArgument, jobject exceptionArgument){
jvmtiError err = (*tiEnv)->StopThread(tiEnv, threadArgument, exceptionArgument);
// error handling
if(err != JVMTI_ERROR_NONE && err != JVMTI_ERROR_THREAD_NOT_ALIVE){
char *errorName;
int hasErrorName = (*tiEnv)->GetErrorName(tiEnv, err, &errorName) == JVMTI_ERROR_NONE;
if(!hasErrorName){
errorName = "<unknown>";
}
char finalError[256];
snprintf(
finalError,
sizeof(finalError),
"Cannot stop thread due to JVMTI error [%d]: %s",
err,
errorName
);
if(hasErrorName)
(*tiEnv)->Deallocate(tiEnv, (unsigned char *)errorName);
(*env)->ThrowNew(env, exceptionClass, finalError);
}
}