[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-serviceability-dev
Subject:    Re: Possible race in jdwp invoke handling?
From:       "serguei.spitsyn () oracle ! com" <serguei ! spitsyn () oracle ! com>
Date:       2017-06-01 9:08:31
Message-ID: c43483a0-323a-dd67-e654-b2019251c691 () oracle ! com
[Download RAW message or body]

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
>
>
>
>
>
>

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic