Hi Thomas,

I'll look at it a couple of days later as I'm busy with other stuff now.

Thanks,
Serguei


On 5/31/17 07:42, Thomas Stüfe wrote:
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







Reply via email to