Execution hang on v8::debug::EvaluateGlobal with kDisableBreaksAndThrowOnSideEffect

114 views
Skip to first unread message

Eduardo Speroni

unread,
Feb 21, 2022, 4:33:22 PM2/21/22
to v8-users
Hello!

We're trying to upgrade the v8 runtime to 9.7 in NativeScript but ran into this issue when implementing the code for enabling the inspector console.


After that the thread hangs. Pausing the app shows the following stack trace:

syscall 0x00000073f171d35c __futex_wait_ex(void volatile*, bool, int, bool, timespec const*) 0x00000073f1721984 pthread_cond_wait 0x00000073f1781b90 v8::internal::OptimizingCompileDispatcher::FlushQueues(v8::internal::BlockingBehavior, bool) 0x00000070cd85c348 v8::internal::OptimizingCompileDispatcher::Flush(v8::internal::BlockingBehavior) 0x00000070cd85c3b4 v8::internal::Debug::DeoptimizeFunction(v8::internal::Handle<v8::internal::SharedFunctionInfo>) 0x00000070cd576324 v8::internal::Runtime_DebugOnFunctionCall(int, unsigned long*, v8::internal::Isolate*) 0x00000070cd8f8b98 Builtins_CEntry_Return1_DontSaveFPRegs_ArgvOnStack_NoBuiltinExit 0x00000070cdb6856c Builtins_CallFunction_ReceiverIsAny 0x00000070cdae25ec Builtins_JSEntryTrampoline 0x00000070cdaebacc Builtins_JSEntry 0x00000070cdaeb768 v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) 0x00000070cd60b6d4 v8::internal::Execution::CallScript(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::FixedArray>) 0x00000070cd60b9d4 v8::internal::DebugEvaluate::Global(v8::internal::Isolate*, v8::internal::Handle<v8::internal::JSFunction>, v8::debug::EvaluateGlobalMode, v8::internal::REPLMode) 0x00000070cd56926c v8::internal::DebugEvaluate::Global(v8::internal::Isolate*, v8::internal::Handle<v8::internal::String>, v8::debug::EvaluateGlobalMode, v8::internal::REPLMode) 0x00000070cd569080 v8::debug::EvaluateGlobal(v8::Isolate*, v8::Local<v8::String>, v8::debug::EvaluateGlobalMode, bool) 0x00000070cd566580 v8_inspector::V8RuntimeAgentImpl::evaluate(v8_inspector::String16 const&, v8_crdtp::detail::ValueMaybe<v8_inspector::String16>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<int>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<double>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<v8_inspector::String16>, std::__Cr::unique_ptr<v8_inspector::protocol::Runtime::Backend::EvaluateCallback, std::__Cr::default_delete<v8_inspector::protocol::Runtime::Backend::EvaluateCallback> >) v8-runtime-agent-impl.cc:309 v8_inspector::protocol::Runtime::DomainDispatcherImpl::evaluate(v8_crdtp::Dispatchable const&) Runtime.cpp:961 v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69::operator()(v8_crdtp::Dispatchable const&) const Runtime.cpp:635 decltype(std::__Cr::forward<v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69&>(fp)(std::__Cr::forward<v8_crdtp::Dispatchable const&>(fp0))) std::__Cr::__invoke<v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69&, v8_crdtp::Dispatchable const&>(v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69&, v8_crdtp::Dispatchable const&) type_traits:3694 void std::__Cr::__invoke_void_return_wrapper<void, true>::__call<v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69&, v8_crdtp::Dispatchable const&>(v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69&, v8_crdtp::Dispatchable const&) __functional_base:348 std::__Cr::__function::__default_alloc_func<v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69, void (v8_crdtp::Dispatchable const&)>::operator()(v8_crdtp::Dispatchable const&) functional:1611 void std::__Cr::__function::__policy_invoker<void (v8_crdtp::Dispatchable const&)>::__call_impl<std::__Cr::__function::__default_alloc_func<v8_inspector::protocol::Runtime::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_69, void (v8_crdtp::Dispatchable const&)> >(std::__Cr::__function::__policy_storage const*, v8_crdtp::Dispatchable const&) functional:2092 v8_crdtp::UberDispatcher::DispatchResult::Run() 0x00000070cd1e2954 v8_inspector::V8InspectorSessionImpl::dispatchProtocolMessage(v8_inspector::StringView) v8-inspector-session-impl.cc:454 tns::JsV8InspectorClient::doDispatchMessage(v8::Isolate*, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> > const&) JsV8InspectorClient.cpp:131 tns::JsV8InspectorClient::dispatchMessage(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> > const&) JsV8InspectorClient.cpp:89 ::Java_com_tns_AndroidJsV8Inspector_dispatchMessage(JNIEnv *, jobject, jstring) com_tns_AndroidJsV8Inspector.cpp:29 art_quick_generic_jni_trampoline 0x00000071422d9a48 art_quick_invoke_stub 0x00000071422d0168 art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*) 0x00000071422f47c8 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x0000007142417a20 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x000000714221660c ExecuteSwitchImplAsm 0x00000071422dc3dc art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) (.llvm.6649268296134209133) 0x0000007142545d58 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.6649268296134209133) 0x000000714227e2f0 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000071423851d4 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x0000007142417c98 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x00000071422166a0 ExecuteSwitchImplAsm 0x00000071422dc3dc art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) (.llvm.6649268296134209133) 0x0000007142545d58 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.6649268296134209133) 0x000000714227e2f0 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000071423851d4 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x0000007142417c98 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x0000007142210704 ExecuteSwitchImplAsm 0x00000071422dc3dc art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) (.llvm.6649268296134209133) 0x0000007142545d58 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.6649268296134209133) 0x000000714227e2f0 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000071423851d4 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x0000007142417c98 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x000000714221660c ExecuteSwitchImplAsm 0x00000071422dc3dc art::interpreter::ExecuteSwitch(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool) (.llvm.6649268296134209133) 0x0000007142545d58 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.6649268296134209133) 0x000000714227e2f0 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000071423851d4 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x0000007142417c98 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x0000007142210704 ExecuteSwitchImplAsm 0x00000071422dc3dc MterpInvokeStatic 0x0000007142775dc0 mterp_op_invoke_static 0x00000071422caa18 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.6649268296134209133) 0x000000714227dd78 artQuickToInterpreterBridge 0x000000714227cf20 art_quick_to_interpreter_bridge 0x00000071422d9b7c <unknown> 0x00000071422d9d90



I believe the code is hanging on this line exactly:


but I can't find out why. Checking the other threads it doesn't seem there are any v8 calls hanging. If we switch to kDisableBreaks or kDefault then the app doesn't hang anymore, but the behavior still isn't correct.

Any insight would be greatly appreciated! Thanks

Igor Randjelovic

unread,
Feb 21, 2022, 8:15:59 PM2/21/22
to v8-users
Hello, I'm also from the NativeScript team...

Another case that we found to hang the same way is whenever we handle the `Debugger.setBreakpointByUrl` protocol message, in which case we see the following stack:

v8_inspector::(anonymous namespace)::ActualScript::setBreakpoint(v8_inspector::String16 const&, v8::debug::Location*, int*) const v8-debugger-script.cc:255 v8_inspector::V8DebuggerAgentImpl::setBreakpointImpl(v8_inspector::String16 const&, v8_inspector::String16 const&, v8_inspector::String16 const&, int, int) v8-debugger-agent-impl.cc:953 v8_inspector::V8DebuggerAgentImpl::setBreakpointByUrl(int, v8_crdtp::detail::ValueMaybe<v8_inspector::String16>, v8_crdtp::detail::ValueMaybe<v8_inspector::String16>, v8_crdtp::detail::ValueMaybe<v8_inspector::String16>, v8_crdtp::detail::ValueMaybe<int>, v8_crdtp::detail::ValueMaybe<v8_inspector::String16>, v8_inspector::String16*, std::__Cr::unique_ptr<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::Location, std::__Cr::default_delete<v8_inspector::protocol::Debugger::Location> >, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::Location, std::__Cr::default_delete<v8_inspector::protocol::Debugger::Location> > > >, std::__Cr::default_delete<std::__Cr::vector<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::Location, std::__Cr::default_delete<v8_inspector::protocol::Debugger::Location> >, std::__Cr::allocator<std::__Cr::unique_ptr<v8_inspector::protocol::Debugger::Location, std::__Cr::default_delete<v8_inspector::protocol::Debugger::Location> > > > > >*) v8-debugger-agent-impl.cc:582 v8_inspector::protocol::Debugger::DomainDispatcherImpl::setBreakpointByUrl(v8_crdtp::Dispatchable const&) Debugger.cpp:1333 v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29::operator()(v8_crdtp::Dispatchable const&) const Debugger.cpp:519 decltype(std::__Cr::forward<v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29&>(fp)(std::__Cr::forward<v8_crdtp::Dispatchable const&>(fp0))) std::__Cr::__invoke<v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29&, v8_crdtp::Dispatchable const&>(v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29&, v8_crdtp::Dispatchable const&) type_traits:3694 void std::__Cr::__invoke_void_return_wrapper<void, true>::__call<v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29&, v8_crdtp::Dispatchable const&>(v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29&, v8_crdtp::Dispatchable const&) __functional_base:348 std::__Cr::__function::__default_alloc_func<v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29, void (v8_crdtp::Dispatchable const&)>::operator()(v8_crdtp::Dispatchable const&) functional:1611 void std::__Cr::__function::__policy_invoker<void (v8_crdtp::Dispatchable const&)>::__call_impl<std::__Cr::__function::__default_alloc_func<v8_inspector::protocol::Debugger::DomainDispatcherImpl::Dispatch(v8_crdtp::span<unsigned char>)::$_29, void (v8_crdtp::Dispatchable const&)> >(std::__Cr::__function::__policy_storage const*, v8_crdtp::Dispatchable const&) functional:2092 void std::__Cr::__function::__policy_invoker<void ()>::__call_impl<std::__Cr::__function::__default_alloc_func<v8_crdtp::UberDispatcher::Dispatch(v8_crdtp::Dispatchable const&) const::$_0, void ()> >(std::__Cr::__function::__policy_storage const*) 0x00000000b91e6ee1 v8_crdtp::UberDispatcher::DispatchResult::Run() 0x00000000b91e516a v8_inspector::V8InspectorSessionImpl::dispatchProtocolMessage(v8_inspector::StringView) v8-inspector-session-impl.cc:451 tns::JsV8InspectorClient::doDispatchMessage(v8::Isolate*, std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> > const&) JsV8InspectorClient.cpp:131 tns::JsV8InspectorClient::dispatchMessage(std::__Cr::basic_string<char, std::__Cr::char_traits<char>, std::__Cr::allocator<char> > const&) JsV8InspectorClient.cpp:89 ::Java_com_tns_AndroidJsV8Inspector_dispatchMessage(JNIEnv *, jobject, jstring) com_tns_AndroidJsV8Inspector.cpp:29 art_quick_generic_jni_trampoline 0x00000000e400b2b3 art_quick_invoke_stub 0x00000000e4004aa3 art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*) 0x00000000e4099502 art::interpreter::ArtInterpreterToCompiledCodeBridge(art::Thread*, art::ArtMethod*, art::ShadowFrame*, unsigned short, art::JValue*) 0x00000000e424f882 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x00000000e4243bbf void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x00000000e4017fcf ExecuteSwitchImplAsm 0x00000000e400bf63 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.10914192770458939989) 0x00000000e4238e02 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000000e4242da0 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x00000000e4243ba1 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x00000000e4017d01 ExecuteSwitchImplAsm 0x00000000e400bf63 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.10914192770458939989) 0x00000000e4238e02 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000000e4242da0 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x00000000e4243ba1 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x00000000e4016381 ExecuteSwitchImplAsm 0x00000000e400bf63 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.10914192770458939989) 0x00000000e4238e02 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000000e4242da0 bool art::interpreter::DoCall<false, false>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x00000000e4243ba1 void art::interpreter::ExecuteSwitchImplCpp<false, false>(art::interpreter::SwitchImplContext*) 0x00000000e4017fcf ExecuteSwitchImplAsm 0x00000000e400bf63 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.10914192770458939989) 0x00000000e4238e02 art::interpreter::ArtInterpreterToInterpreterBridge(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*, art::JValue*) 0x00000000e4242da0 bool art::interpreter::DoCall<false, true>(art::ArtMethod*, art::Thread*, art::ShadowFrame&, art::Instruction const*, unsigned short, art::JValue*) 0x00000000e4244636 void art::interpreter::ExecuteSwitchImplCpp<true, false>(art::interpreter::SwitchImplContext*) 0x00000000e4057794 ExecuteSwitchImplAsm 0x00000000e400bf63 art::interpreter::Execute(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame&, art::JValue, bool, bool) (.llvm.10914192770458939989) 0x00000000e4238c0f art::interpreter::EnterInterpreterFromEntryPoint(art::Thread*, art::CodeItemDataAccessor const&, art::ShadowFrame*) 0x00000000e4242c81 artQuickToInterpreterBridge 0x00000000e4656186 art_quick_to_interpreter_bridge 0x00000000e400b38e <unknown> 0x00000000e400b530

As Eduardo mentioned, any hints or insights would be very appreciated!

Thanks,
Igor

Jakob Gruber

unread,
Feb 22, 2022, 1:18:04 AM2/22/22
to v8-u...@googlegroups.com
Looks to me like a deadlock between

  if (blocking_behavior == BlockingBehavior::kBlock) {
    base::MutexGuard lock_guard(&ref_count_mutex_);
    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);



and

      base::MutexGuard lock_guard(&dispatcher_->ref_count_mutex_);
      if (--dispatcher_->ref_count_ == 0) {



I'm puzzled how this should work, maybe I'm missing something. The ref_count_mutex_ is locked on both sides, so if we enter the while-loop waiting for it to hit zero, we can't actually decrement the ref count.

--
--
v8-users mailing list
v8-u...@googlegroups.com
http://groups.google.com/group/v8-users
---
You received this message because you are subscribed to the Google Groups "v8-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to v8-users+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/v8-users/64391392-e134-4b57-9bd8-b1b7c41f8a5dn%40googlegroups.com.

Jakob Gruber

unread,
Feb 22, 2022, 4:09:49 AM2/22/22
to v8-u...@googlegroups.com
On Tue, Feb 22, 2022 at 7:17 AM Jakob Gruber <jgr...@chromium.org> wrote:
Looks to me like a deadlock between

  if (blocking_behavior == BlockingBehavior::kBlock) {
    base::MutexGuard lock_guard(&ref_count_mutex_);
    while (ref_count_ > 0) ref_count_zero_.Wait(&ref_count_mutex_);



and

      base::MutexGuard lock_guard(&dispatcher_->ref_count_mutex_);
      if (--dispatcher_->ref_count_ == 0) {



I'm puzzled how this should work, maybe I'm missing something. The ref_count_mutex_ is locked on both sides, so if we enter the while-loop waiting for it to hit zero, we can't actually decrement the ref count.

Indeed I missed the (obvious in hindsight) `ref_count_zero_.Wait(&ref_count_mutex_);` call, thanks tebbi@ for pointing that out.

Eduardo Speroni

unread,
Feb 23, 2022, 3:10:26 PM2/23/22
to v8-users
Thanks for taking the time to look into this!

What would be a suitable patch we could apply to fix this? Hopefully we can patch V8 on our end and test a couple other scenarios.

Thank you again!

Reply all
Reply to author
Forward
0 new messages