Possible race in jdwp invoke handling?
Thomas Stüfe
thomas.stuefe at gmail.com
Wed May 31 14:42:44 UTC 2017
Hi all,
I am looking at a possible race in JDWP invoke request handling and would
like your opinion.
This is how I understand the handling of invoke events (please do correct
me if I am wrong):
1) JDWP InvokeXXX request comes in for thread X. Handled by the "JDWP
Transport Listener" thread. We call "invoker_requestInvoke()". Here, under
lock protection, we take the thread-local InvokeRequest structure and fill
it with the invoke data. We only do this if request->available is true. We
set request->available to false, thereby preventing further attempts to add
invoke requests for this thread. Any subsequent JDWP invoke commands will
now return with errors, right?
2) In the context of a JVMTI callback for thread X the actual invoke will
be done. Request structure will be filled with the result (exception object
handle and result). request->available stays false.
3) In a third thread, the "JDWP Event Helper Thread", the return packet
will be sent to the debugger. In invoker_completeInvokeRequest(), we have
two guarded sections. In the first section, we reset request->available to
true (A):
eventHandler_lock(); /* for proper lock order */
debugMonitorEnter(invokerLock);
request = threadControl_getInvokeRequest(thread);
....<skip>...
request->pending = JNI_FALSE;
request->started = JNI_FALSE;
A) request->available = JNI_TRUE; /* For next time around */
...<skip>...
debugMonitorExit(invokerLock);
eventHandler_unlock();
Then we leave the guarded section and send the jdwp answer packet back.
Then we enter a second guarded section and clean up the handles for return
value and exception:
...
eventHandler_lock(); // for proper lock order
debugMonitorEnter(invokerLock);
B) deletePotentiallySavedGlobalRefs(env, request);
debugMonitorExit(invokerLock);
eventHandler_unlock();
---
My question is this: would it be possible for a new invoke request to be
incoming in the time between the first and the second guarded section? So,
could the following sequence happen:
[JDWP Transport Listener] invoker_requestInvoke (request 1)
[Thread X] invoker_doInvoke (request 1)
[JDWP Event Helper] invoker_completeInvokeRequest
(request 1)
debugMonitorEnter(invokerLock);
<reset
request->available and request->pending>
debugMonitorExit(invokerLock);
....
[JDWP Transport Listener] invoker_requestInvoke (request 2)
[Thread X] invoker_doInvoke (request
2) -> overwrites request->exception and request->returnValue to its new
values.
[JDWP Event Helper] ....
debugMonitorEnter(invokerLock);
deletePotentiallySavedGlobalRefs(env, request); -> releases
request->exception and request->returnValue, which is now interfering with
request 2.
debugMonitorExit(invokerLock);
?
This is all theoretical. Wanted to hear your opinions first before
proceeding.
Kind Regards, Thomas
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.openjdk.java.net/pipermail/serviceability-dev/attachments/20170531/008c07dd/attachment.html>
More information about the serviceability-dev
mailing list