Deadlock with the V8-debugger-agent-thread when deleting V8ScriptEngine after a debug session

Sep 20, 2013 at 4:03 PM
Edited Sep 20, 2013 at 4:29 PM
To setup eclipse, I used this tutorial (https://github.com/joyent/node/wiki/Using-Eclipse-as-Node-Applications-Debugger) ; and selected "Standalone V8 VM" in "Run/Debug Configurations...".

I ran the following test code with nunit and attached the eclipse debugger (during the Thread.Sleep -- dirty but no other options for this now).
And when destroying the V8ScriptEngine, the debugger side said "terminated", the script side deadlocked. 32 or 64 bitness does not seems to make a difference. I can reproduce this every time.
        [Test]
        public virtual void Test_Attach_Debugger()
        {
            using (var engine = new V8ScriptEngine("Crash test debug script", V8ScriptEngineFlags.EnableDebugging, 9222))
            {
                engine.Execute("Document0.js", @"
function fun0() {
//whatever
}

");
                Thread.Sleep(10000); // We cannot wait for the debugger with clearscript (yet?)s
                engine.Execute("Document1.js", @"

function stuff() {
// whatever}
}
stuff();
");
            }
        }
I had the following stack trace on running thread (0x2F38) :
(the debugger shows that the thread we want to Join is 0x215C)
    ntdll.dll!NtWaitForSingleObject()  + 0xa bytes  
    KernelBase.dll!WaitForSingleObjectEx()  + 0x9c bytes    
    v8-x64.dll!v8::internal::Thread::Join()  Line 1672  C++
    v8-x64.dll!v8::internal::DebuggerAgent::CloseSession()  Line 132    C++
    v8-x64.dll!v8::internal::DebuggerAgent::Shutdown()  Line 98 C++
    v8-x64.dll!v8::internal::Debugger::StopAgent()  Line 3458   C++
    v8-x64.dll!v8::Debug::DisableAgent()  Line 7431 C++
    ClearScriptV8-64.dll!V8IsolateImpl::DisableDebugging()  Line 218    C++
    ClearScriptV8-64.dll!V8IsolateImpl::~V8IsolateImpl()  Line 316 + 0xd bytes  C++
    ClearScriptV8-64.dll!V8IsolateImpl::`scalar deleting destructor'()  + 0x17 bytes    C++
    ClearScriptV8-64.dll!SharedPtr<V8IsolateImpl>::Release()  Line 286 + 0x34 bytes C++
    ClearScriptV8-64.dll!SharedPtr<V8IsolateImpl>::~SharedPtr<V8IsolateImpl>()  Line 246    C++
    ClearScriptV8-64.dll!V8ContextImpl::~V8ContextImpl()  Line 587 + 0x29 bytes C++
    ClearScriptV8-64.dll!V8ContextImpl::`scalar deleting destructor'()  + 0x17 bytes    C++
    [Managed to Native Transition]  
    ClearScriptV8-64.dll!SharedPtr<V8Context>::Release() Line 286 + 0x3d bytes  C++
    ClearScriptV8-64.dll!SharedPtr<V8Context>::~SharedPtr<V8Context>() Line 245 + 0xa bytes C++
    ClearScriptV8-64.dll!Microsoft::ClearScript::V8::V8ContextProxyImpl::~V8ContextProxyImpl() Line 239 + 0x9 bytes C++
    ClearScriptV8-64.dll!Microsoft::ClearScript::V8::V8ContextProxyImpl::Dispose(bool A_0 = true) + 0x3d bytes  C++
    ClearScriptV8-64.dll!Microsoft.ClearScript.V8.V8ContextProxyImpl.Dispose() + 0x34 bytes 
    ClearScript.dll!Microsoft.ClearScript.V8.V8ScriptEngine.Dispose(bool disposing = true) Line 704 + 0x25 bytes    C#
    ClearScript.dll!Microsoft.ClearScript.ScriptEngine.Dispose() Line 1007 + 0x16 bytes C#
>   XXXXX.Javascript.Test.dll!XXXXX.Javascript.Test.TestJs.Test_Attach_Debugger() Line 718 + 0x3f bytes C#
    [Native to Managed Transition]  
    nunit.core.dll!NUnit.Core.Reflect.InvokeMethod(System.Reflection.MethodInfo method, object fixture, object[] args) + 0x51 byte
       ........
The thread (0x215C) we are waiting for has the following stack trace and also waits for a critical section... which is owned by runner thread 0x2F38 (hence the deadlock) :

```
ntdll.dll!NtWaitForSingleObject()  + 0xa bytes  
ntdll.dll!RtlpWaitOnCriticalSection()  + 0xe8 bytes 
ntdll.dll!RtlEnterCriticalSection()  - 0x4b75 bytes
v8-x64.dll!v8::internal::Win32Mutex::Lock()  Line 1723  C++
v8-x64.dll!v8::internal::ThreadManager::Lock()  Line 218    C++
v8-x64.dll!v8::Locker::Initialize(v8::Isolate * isolate=0x000000001f3281e0)  Line 62    C++
ClearScriptV8-64.dll!v8::Locker::Locker(v8::Isolate * isolate=0x000000001f3281e0)  Line 5286 + 0x1d bytes   C++
ClearScriptV8-64.dll!V8IsolateImpl::Scope::Scope(V8IsolateImpl * pIsolateImpl=0x0000000000ab81f0)  Line 91 + 0x2d bytes C++
ClearScriptV8-64.dll!V8IsolateImpl::~V8IsolateImpl()  Line 314 + 0x21 bytes C++
ClearScriptV8-64.dll!V8IsolateImpl::`scalar deleting destructor'()  + 0x17 bytes    C++
ClearScriptV8-64.dll!SharedPtr<V8Isolate>::Release()  Line 286 + 0x34 bytes C++
ClearScriptV8-64.dll!SharedPtr<V8Isolate>::~SharedPtr<V8Isolate>()  Line 246    C++
ClearScriptV8-64.dll!<lambda_7e4a4414a5bed1a06c00faa4d01241d8>::operator()()  Line 197 + 0xa bytes  C++
ClearScriptV8-64.dll!std::_Callable_obj<<lambda_7e4a4414a5bed1a06c00faa4d01241d8>,0>::_ApplyX<void>()  Line 431 + 0x1b bytes    C++ ClearScriptV8-64.dll!std::_Func_impl<std::_Callable_obj<<lambda_7e4a4414a5bed1a06c00faa4d01241d8>,0>,std::allocator<std::_Func_class<void,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil> >,void,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::_Do_call()  Line 239 + 0x1a bytes   C++
ClearScriptV8-64.dll!std::_Func_class<void,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil,std::_Nil>::operator()()  Line 514 + 0x33 bytes  C++
ClearScriptV8-64.dll!CallbackSlot<DebugMessageDispatcherCallbackTraits,0,void __cdecl(void)>::Callback()  Line 144 + 0x23 bytes C++
v8-x64.dll!v8::internal::Debugger::CallMessageDispatchHandler()  Line 3481  C++
v8-x64.dll!v8::internal::Debugger::ProcessCommand(v8::internal::Vector<unsigned short const > command={...}, v8::Debug::ClientData * client_data=0x0000000000000000)  Line 3361 C++
v8-x64.dll!v8::Debug::SendCommand(const unsigned short * command=0x000000001b731400, int length=0x00000031, v8::Debug::ClientData * client_data=0x0000000000000000, v8::Isolate * isolate=0x000000001f3281e0)  Line 7349    C++
v8-x64.dll!v8::internal::DebuggerAgentSession::Run()  Line 206  C++
v8-x64.dll!v8::internal::Thread::NotifyStartedAndRun()  Line 703    C++
v8-x64.dll!v8::internal::ThreadEntry(void * arg=0x000000001b7e7770)  Line 1617  C++
msvcr110d.dll!_callthreadstartex()  Line 354 + 0x17 bytes   C
msvcr110d.dll!_threadstartex(void * ptd=0x000000001f3b2410)  Line 337   C
kernel32.dll!BaseThreadInitThunk()  + 0xd bytes 
ntdll.dll!RtlUserThreadStart()  + 0x21 bytes    
````
Coordinator
Sep 20, 2013 at 5:46 PM
Hi julien_b,

The stack traces are very helpful; we're investigating.

Thanks!
Coordinator
Sep 21, 2013 at 4:27 PM
Hi julien_b,

We've posted a potential fix. We were able to reproduce the deadlock but not the "wrong AppDomain" crash, but because the code flaw could cause memory corruption, that message may be a red herring. When you get a chance, could you please download the latest source code and retry your tests?

Please be aware that there are known issues with the Eclipse-based debugger that are still unresolved:
  • Host object properties are shown as "undefined" in several views, but can be evaluated correctly in the Expressions window.
  • Be careful when using the "Step Over" function in the debugger. If "Step Over" returns control to the host application, the debugger may get out of sync with the V8 runtime. Until this is fixed, use "Resume" to return control to the host application.
Thanks for your help!