FoxxMD / multi-scrobbler

Scrobble plays from multiple sources to multiple clients
https://foxxmd.github.io/multi-scrobbler
MIT License
299 stars 14 forks source link

Node debugger crashes with SIGSEGV in mocha tests when evaluating variable in static class function #143

Closed FoxxMD closed 3 months ago

FoxxMD commented 4 months ago

If mocha tests are run while debugging node then a listenbrainz test that accesses the static method listenResponseToPlay nodejs crashes with SIGSEGV.

NODE_INSPECT_RESUME_ON_START=1 ~/node-18.19.1/out/Debug/node ~/multi-scrobbler/node_modules/mocha/bin/mocha.js inspect --timeout 0 ~/multi-scrobbler/src/backend/tests/listenbrainz/listenbrainz.test.ts

On break run:

debug> exec('listened_at')

Produces this error:

< #
< # Fatal error in ../../deps/v8/src/debug/debug-scopes.cc, line 135
< # Debug check failed: (closure_scope_) != nullptr.
< #
< #
< #
< #FailureMessage Object: 0x7ffff41e55d0
< 
<  1: 0x5b3fc8d07f7b node::DumpBacktrace(_IO_FILE*) [~/node-18.19.1/out/Debug/node]
< 
<  2: 0x5b3fc8ee6689  [~/node-18.19.1/out/Debug/node]
< 
<  3: 0x5b3fc8ee66a9  [~/node-18.19.1/out/Debug/node]
< 
<  4: 0x5b3fcabeabb6 V8_Fatal(char const*, int, char const*, ...) [~/node-18.19.1/out/Debug/node]
< 
<  5: 0x5b3fcabeabe5  [~/node-18.19.1/out/Debug/node]
< 
<  6: 0x5b3fc932debb v8::internal::ScopeIterator::TryParseAndRetrieveScopes(v8::internal::ScopeIterator::ReparseStrategy) [~/node-18.19.1/out/Debug/node]
< 
<  7: 0x5b3fc930bddb v8::internal::DebugEvaluate::ContextBuilder::ContextBuilder(v8::internal::Isolate*, v8::internal::JavaScriptFrame*, int) [~/node-18.19.1/out/Debug/node]
< 
<  8: 0x5b3fc930e9d4 v8::internal::DebugEvaluate::Local(v8::internal::Isolate*, v8::internal::StackFrameId, int, v8::internal::Handle<v8::internal::String>, bool) [~/node-18.19.1/out/Debug/node]
< 
<  9: 0x5b3fc932f3e2 v8::internal::DebugStackTraceIterator::Evaluate(v8::Local<v8::String>, bool) [~/node-18.19.1/out/Debug/node]
< 
< 10: 0x5b3fc9c3c54e v8_inspector::V8DebuggerAgentImpl::evaluateOnCallFrame(v8_inspector::String16 const&, 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<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<bool>, v8_crdtp::detail::ValueMaybe<double>, std::unique_ptr<v8_inspector::protocol::Runtime::RemoteObject, std::default_delete<v8_inspector::protocol::Runtime::RemoteObject> >*, v8_crdtp::detail::PtrMaybe<v8_inspector::protocol::Runtime::ExceptionDetails>*) [~/node-18.19.1/out/Debug/node]
< 
< 11: 0x5b3fc90bd81f v8_inspector::protocol::Debugger::DomainDispatcherImpl::evaluateOnCallFrame(v8_crdtp::Dispatchable const&) [~/node-18.19.1/out/Debug/node]
< 
< 12: 0x5b3fc9c8679a v8_crdtp::UberDispatcher::DispatchResult::Run() [~/node-18.19.1/out/Debug/node]
< 
< 13: 0x5b3fc9c4b4e7 v8_inspector::V8InspectorSessionImpl::dispatchProtocolMessage(v8_inspector::StringView) [~/node-18.19.1/out/Debug/node]
< 
< 14: 0x5b3fc8fddcf0  [~/node-18.19.1/out/Debug/node]
< 
< 15: 0x5b3fc8fdedb2 node::inspector::NodeInspectorClient::dispatchMessageFromFrontend(int, v8_inspector::StringView const&) [~/node-18.19.1/out/Debug/node]
< 
< 16: 0x5b3fc8fda194  [~/node-18.19.1/out/Debug/node]
< 
< 17: 0x5b3fc900d08a  [~/node-18.19.1/out/Debug/node]
< 
< 18: 0x5b3fc900f129  [~/node-18.19.1/out/Debug/node]
< 
< 19: 0x5b3fc9012be4  [~/node-18.19.1/out/Debug/node]
< 
< 20: 0x5b3fc901278f  [~/node-18.19.1/out/Debug/node]
< 
< 21: 0x5b3fc9012255  [~/node-18.19.1/out/Debug/node]
< 
< 22: 0x5b3fc9011f2a  [~/node-18.19.1/out/Debug/node]
< 
< 23: 0x5b3fc9011d4a  [~/node-18.19.1/out/Debug/node]
< 
< 24: 0x5b3fc900d986 node::inspector::MainThreadInterface::DispatchMessages() [~/node-18.19.1/out/Debug/node]
< 
< 25: 0x5b3fc900d604  [~/node-18.19.1/out/Debug/node]
< 
< 26: 0x5b3fc9011cf3  [~/node-18.19.1/out/Debug/node]
< 
< 27: 0x5b3fc8d3689f node::Environment::RunAndClearInterrupts() [~/node-18.19.1/out/Debug/node]
< 
< 28: 0x5b3fc8fdfa80 node::inspector::NodeInspectorClient::runMessageLoop() [~/node-18.19.1/out/Debug/node]
< 
< 29: 0x5b3fc8fde564 node::inspector::NodeInspectorClient::runMessageLoopOnPause(int) [~/node-18.19.1/out/Debug/node]
< 
< 30: 0x5b3fc9c20c45 v8_inspector::V8Debugger::handleProgramBreak(v8::Local<v8::Context>, v8::Local<v8::Value>, std::vector<int, std::allocator<int> > const&, v8::base::EnumSet<v8::debug::BreakReason, int>, v8::debug::ExceptionType, bool) [~/node-18.19.1/out/Debug/node]
< 
< 31: 0x5b3fc9c20ce6 v8_inspector::V8Debugger::BreakProgramRequested(v8::Local<v8::Context>, std::vector<int, std::allocator<int> > const&, v8::base::EnumSet<v8::debug::BreakReason, int>) [~/node-18.19.1/out/Debug/node]
< 
< 32: 0x5b3fc93452bd v8::internal::Debug::OnDebugBreak(v8::internal::Handle<v8::internal::FixedArray>, v8::internal::StepAction, v8::base::EnumSet<v8::debug::BreakReason, int>) [~/node-18.19.1/out/Debug/node]
< 
< 33: 0x5b3fc93454ca v8::internal::Debug::HandleDebugBreak(v8::internal::IgnoreBreakMode, v8::base::EnumSet<v8::debug::BreakReason, int>) [~/node-18.19.1/out/Debug/node]
< 
< 34: 0x5b3fc9ad2693 v8::internal::Runtime_HandleDebuggerStatement(int, unsigned long*, v8::internal::Isolate*) [~/node-18.19.1/out/Debug/node]
< 
< 35: 0x5b3fca0bc239  [~/node-18.19.1/out/Debug/node]

The error produced and required conditions seem extremely similar to https://github.com/nodejs/node/issues/46578

It's important to note this only occurs when debugging nodejs, breaking in the method, and evaluating an expression. It does not occur for normal tests (not debugging) or normal usage of MS.

FoxxMD commented 4 months ago

Changes that fix the crash:

Use normal static method

Instead of using arrow function form for class static method use the normal form. This does not cause the debugger to crash.

It's probably a good idea to do a refactor for all class methods to avoid using fat arrow due to this limitations, anyway.

Upgrade to Node 20.x

As mentioned in https://github.com/nodejs/node/issues/46578 upgrading to 20.x causes debugger to not crash even when using fat arrow static methods.