Skip to content

inspector: Debugger.setAsyncCallStackDepth after waitingForDisconnect event crashes worker #28528

Closed
@alexkozy

Description

  • Version: v12.5.0
  • Platform: Mac
  • Subsystem: inspector

Create a snippet with following content to reproduce the crash:

const { Worker } = require('worker_threads');
const inspector = require('inspector');
(async function main() {
  inspector.open(0, undefined, false);
  const session = new inspector.Session;
  await session.connect();
  await session.post('NodeWorker.enable', { waitForDebuggerOnStart: true});
  session.on('NodeWorker.attachedToWorker', async({params:{sessionId}}) => {
    // enable debugger, otherwise setAsyncCallStackDepth does nothing
    session.post('NodeWorker.sendMessageToWorker', {
      sessionId,
      message: JSON.stringify({id: 1, method: 'Debugger.enable'})
    });
    // enable waiting for disconnect notification
    session.post('NodeWorker.sendMessageToWorker', {
      sessionId,
      message: JSON.stringify({id: 2, method: 'NodeRuntime.notifyWhenWaitingForDisconnect', params: {enabled: true}})
    });
    // start worker
    session.post('NodeWorker.sendMessageToWorker', {
      sessionId,
      message: JSON.stringify({id: 3, method: 'Runtime.runIfWaitingForDebugger'})
    });
    // wait for notification
    await new Promise(resolve => session.on('NodeWorker.receivedMessageFromWorker', ({params:{message}}) => {
      if (JSON.parse(message).method === 'NodeRuntime.waitingForDisconnect')
        resolve();
    }));
    // force call to node::inspector::Agent::ToggleAsyncHook by changing async call stack depth
    await session.post('NodeWorker.sendMessageToWorker', {
      sessionId,
      message: JSON.stringify({id: 4, method: 'Debugger.setAsyncCallStackDepth', params: {maxDepth: 1}})
    });
    // BOOM!
   await session.post('NodeWorker.detach', {
      sessionId,
    });
  });
  new Worker('console.log(42)', { eval: true });
})()

node crashes with following stack trace on node::inspector::Agent::ToggleAsyncHook call:

FATAL ERROR: 
node::inspector::Agent::ToggleAsyncHook Cannot toggle Inspector's AsyncHook, please report this.
 1: 0x10007643b node::Abort()
 2: 0x100076b7c node::errors::TryCatchScope::~TryCatchScope()
 3: 0x100076a0e node::OnFatalError(char const*, char const*)
 4: 0x100106baf node::inspector::Agent::ToggleAsyncHook(v8::Isolate*, v8::Global<v8::Function> const&)
 5: 0x10074cf63 v8_inspector::V8Debugger::setAsyncCallStackDepth(v8_inspector::V8DebuggerAgentImpl*, int)
 6: 0x10075e964 v8_inspector::V8DebuggerAgentImpl::setAsyncCallStackDepth(int)
 7: 0x100826369 v8_inspector::protocol::Debugger::DispatcherImpl::setAsyncCallStackDepth(int, v8_inspector::String16 const&, v8_inspector::protocol::ProtocolMessage const&, std::__1::unique_ptr<v8_inspector::protocol::DictionaryValue, std::__1::default_delete<v8_inspector::protocol::DictionaryValue> >, v8_inspector::protocol::ErrorSupport*)
 8: 0x100822d64 v8_inspector::protocol::Debugger::DispatcherImpl::dispatch(int, v8_inspector::String16 const&, v8_inspector::protocol::ProtocolMessage const&, std::__1::unique_ptr<v8_inspector::protocol::DictionaryValue, std::__1::default_delete<v8_inspector::protocol::DictionaryValue> >)
 9: 0x1008016a8 v8_inspector::protocol::UberDispatcher::dispatch(int, v8_inspector::String16 const&, std::__1::unique_ptr<v8_inspector::protocol::Value, std::__1::default_delete<v8_inspector::protocol::Value> >, v8_inspector::protocol::ProtocolMessage const&)
10: 0x10076da2a v8_inspector::V8InspectorSessionImpl::dispatchProtocolMessage(v8_inspector::StringView const&)
11: 0x100107cd5 node::inspector::NodeInspectorClient::dispatchMessageFromFrontend(int, v8_inspector::StringView const&)
12: 0x100107a1c node::inspector::(anonymous namespace)::SameThreadInspectorSession::Dispatch(v8_inspector::StringView const&)
13: 0x100114fda void node::inspector::(anonymous namespace)::AnotherThreadObjectReference<node::inspector::(anonymous namespace)::MainThreadSessionState>::Apply<std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> > >(node::inspector::(anonymous namespace)::MainThreadSessionState*, void (node::inspector::(anonymous namespace)::MainThreadSessionState::*)(std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >), std::__1::unique_ptr<v8_inspector::StringBuffer, std::__1::default_delete<v8_inspector::StringBuffer> >&)
14: 0x1001140f1 node::inspector::MainThreadInterface::DispatchMessages()
15: 0x1000c8728 node::PerIsolatePlatformData::RunForegroundTask(std::__1::unique_ptr<v8::Task, std::__1::default_delete<v8::Task> >)
16: 0x1000c7b74 node::PerIsolatePlatformData::FlushForegroundTasksInternal()
17: 0x1000c8abb node::NodePlatform::FlushForegroundTasks(v8::Isolate*)
18: 0x1001071bd node::inspector::NodeInspectorClient::runMessageLoop()
19: 0x10010659f node::inspector::Agent::WaitForDisconnect()
20: 0x1000e054f std::__1::__function::__func<node::worker::Worker::Run()::$_0, std::__1::allocator<node::worker::Worker::Run()::$_0>, void ()>::operator()()
21: 0x1000a574f node::OnScopeLeave::~OnScopeLeave()
22: 0x1000ddd2f node::worker::Worker::Run()
23: 0x1000dfbbb node::worker::Worker::StartThread(v8::FunctionCallbackInfo<v8::Value> const&)::$_2::__invoke(void*)
24: 0x7fff692672eb _pthread_body [/usr/lib/system/libsystem_pthread.dylib]
25: 0x7fff6926a249 _pthread_start [/usr/lib/system/libsystem_pthread.dylib]
26: 0x7fff6926640d thread_start [/usr/lib/system/libsystem_pthread.dylib]
Abort trap: 6

I think that root of the issue is invalid state of node isolate when it is waiting for disconnect.

cc @eugeneo

Metadata

Assignees

No one assigned

    Labels

    inspectorIssues and PRs related to the V8 inspector protocol

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions