inspector: Runtime.evaluate with the contextId of a just-collected vm context segfaults

未關閉
#67,138 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
42/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
cpp, javascript, node.js
領域
devtools

研究方向

Run the target.js and client.mjs reproduction first; it should currently exit with SIGSEGV when Runtime.evaluate targets a collected context. Read the cited V8 src/inspector/inspected-context.cc path and the backtrace through InjectedScript::Scope::initialize; the report notes the fix may belong in V8. Done means the target reliably finishes and evaluating a missing context returns “Cannot find context with specified id.”

由索引模型根據 Issue 內容生成。

描述

Version

v22.23.4, v24.22.2, v26.13.0 with the repro below; v24.21.0 in the backtrace further down

Platform

Linux x64 (Ubuntu 22.04 container and Debian bookworm node images), Linux arm64 (node:26-slim)

Subsystem

inspector

What steps will reproduce the bug?

target.js:

const vm = require('node:vm');
let n = 0;
function step() {
  vm.runInNewContext('1');
  let junk = [];
  const t = Date.now();
  while (Date.now() - t < 3) {
    junk.push({ n });
    if (junk.length > 1e5) junk = [];
  }
  if (++n < 2000) setImmediate(step);
  else console.log('finished', n);
}
step();

client.mjs, in the same directory:

import { spawn } from 'node:child_process';

const child = spawn(process.execPath, ['--inspect-brk=127.0.0.1:0', new URL('target.js', import.meta.url).pathname], { stdio: ['ignore', 'inherit', 'pipe'] });
let ws;
child.stderr.on('data', (d) => {
  const url = String(d).match(/ws:\/\/\S+/);
  if (url && !ws) connect(url[0]);
  if (/Waiting for the debugger to disconnect/.test(d)) ws.close();
});
child.on('exit', (code, signal) => console.log(`target exited: code=${code} signal=${signal}`));

function connect(url) {
  ws = new WebSocket(url);
  let id = 0;
  const send = (method, params = {}) => ws.send(JSON.stringify({ id: ++id, method, params }));
  ws.onmessage = ({ data }) => {
    const msg = JSON.parse(data);
    if (msg.method === 'Runtime.executionContextCreated' && msg.params.context.id > 1) {
      send('Runtime.evaluate', { expression: '1', contextId: msg.params.context.id });
    }
  };
  ws.onopen = () => {
    send('Runtime.enable');
    send('Runtime.runIfWaitingForDebugger');
  };
}

Run node client.mjs.

How often does it reproduce? Is there a required condition?

Most runs on Linux: 14 of 15 on x64 (Docker on Apple Silicon) across 22, 24 and 26, and 9 of 10 on arm64 with 26.13.0. Without the Runtime.evaluate it always finishes. It didn't reproduce on macOS arm64 with v22.19.0 in 2 runs.

What is the expected behavior? Why is that the expected behavior?

finished 2000 and exit code 0. An evaluate in a context that no longer exists should fail with "Cannot find context with specified id".

What do you see instead?

target exited: code=null signal=SIGSEGV.

Additional information

Backtrace from a real crash (v24.21.0, x64):

#0  v8::Context::Enter()
#1  v8_inspector::InjectedScript::Scope::initialize()
#2  v8_inspector::V8RuntimeAgentImpl::evaluate(...)
...
#9  node::inspector::MainThreadInterface::DispatchMessages()
#14 v8::internal::StackGuard::HandleInterrupts(...)

The context pointer is null. In V8's src/inspector/inspected-context.cc (main today), the weak callback resetContext empties the context handle and posts a foreground task to discard the context. Until that task runs, session->findInjectedScript still finds the context id, and InjectedScript::Scope::initialize calls m_injectedScript->context()->context()->Enter() without checking for an empty handle. An evaluate dispatched by interrupt in that window crashes. If that's right the fix belongs in V8; happy to file it there instead.

We hit it through VS Code's JavaScript debugger, which evaluates a hook in every new context once a breakpoint is set, while require('repl') (pulled in by ts-node) creates a throwaway context: (js-debug issue link).

主要語言
JavaScript
星號
123k
分支
39.3k
平均合併
4 天 16 小時
30 天內合併 PR
227

環境準備

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

nodejs/node 的其他 Issue

查看 nodejs/node 的全部 Issue

相似的 Issue

更多 JavaScript Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。