diff --git a/src/inspector/v8-inspector-session-impl.h b/src/inspector/v8-inspector-session-impl.h index d323b47f3d8..9b782599498 100644 --- a/src/inspector/v8-inspector-session-impl.h +++ b/src/inspector/v8-inspector-session-impl.h @@ -56,6 +56,22 @@ class V8InspectorSessionImpl : public V8InspectorSession, int contextGroupId() const { return m_contextGroupId; } int sessionId() const { return m_sessionId; } + // Pins the session for the lifetime of the scope so re-entrant page JS that + // causes the embedder to drop its shared_ptr (e.g. DevToolsSession::Detach) + // cannot fully destroy the session while inspector code is still on the + // stack. Used by dispatchProtocolMessage and by entry points reached from + // V8 callbacks (console.log -> reportMessage). + class KeepSessionAliveScope { + CPPGC_STACK_ALLOCATED(); + + public: + explicit KeepSessionAliveScope(const V8InspectorSessionImpl& session) + : m_this(session.m_weakThis.lock()) {} + + private: + std::shared_ptr m_this; + }; + Response findInjectedScript( int contextId, InjectedScript*&, std::shared_ptr* inspectedContext = nullptr); @@ -156,20 +172,6 @@ class V8InspectorSessionImpl : public V8InspectorSession, bool use_binary_protocol_ = false; V8Inspector::ClientTrustLevel m_clientTrustLevel = V8Inspector::kUntrusted; - // On each call to "dispatchProtocolMessage", the session turns the weakThis - // reference into a strong one, so nested run loops are not able to fully - // deconstruct the V8 session until we return from the - // "dispatchProtocolMessage" call (i.e. no freed "this" remains on the stack). - class KeepSessionAliveScope { - CPPGC_STACK_ALLOCATED(); - - public: - explicit KeepSessionAliveScope(const V8InspectorSessionImpl& session) - : m_this(session.m_weakThis.lock()) {} - - private: - std::shared_ptr m_this; - }; std::weak_ptr m_weakThis; }; diff --git a/src/inspector/v8-runtime-agent-impl.cc b/src/inspector/v8-runtime-agent-impl.cc index 226a6c74d94..941ba186ce9 100644 --- a/src/inspector/v8-runtime-agent-impl.cc +++ b/src/inspector/v8-runtime-agent-impl.cc @@ -1216,6 +1216,10 @@ void V8RuntimeAgentImpl::messageAdded(V8ConsoleMessage* message) { bool V8RuntimeAgentImpl::reportMessage(V8ConsoleMessage* message, bool generatePreview) { + // reportToFrontend may re-enter page JS (descriptionForError -> prototype + // getter) which can drop the embedder's last ref to the session. Pin it so + // |this| (owned by the session) survives until we return. + V8InspectorSessionImpl::KeepSessionAliveScope keep(*m_session); message->reportToFrontend(&m_frontend, m_session, generatePreview); m_frontend.flush(); return m_inspector->hasConsoleMessageStorage(m_session->contextGroupId());