Skip to content

test(inspector): test report progress case#50

Draft
tony-go wants to merge 6 commits into
mainfrom
fix/inspector-safe-cb
Draft

test(inspector): test report progress case#50
tony-go wants to merge 6 commits into
mainfrom
fix/inspector-safe-cb

Conversation

@tony-go

@tony-go tony-go commented Jul 20, 2026

Copy link
Copy Markdown

HeapProfiler.takeHeapSnapshot with reportProgress: true crashes the process with SIGSEGV. The inspector channel delivers V8 protocol messages by synchronously invoking the embedder callback, which re-enters JavaScript. During heap snapshot generation V8 emits HeapProfiler.reportHeapSnapshotProgress notifications while the stack is being scanned and JS execution is disallowed, so re-entering JS there crashes.

This makes the Chrome DevTools Memory panel unusable against an inspected process, since it requests progress reporting when taking a snapshot.

Root cause

js_inspector_channel_s::send() used to call the response callback inline:

cb(env, inspector, /* message */, len, data);

The crashing path (bare runtime, arm64):

  v8::internal::HeapSnapshotGenerator::GenerateSnapshot()
   └ PushAllRegistersAndIterateStack                 ← stack marker set, JS forbidden
     └ V8HeapExplorer::IterateAndExtractReferences
       └ reportHeapSnapshotProgress                  ← V8 emits the notification
         └ js_inspector_channel_s::send
           └ <embedder callback>
             └ v8::Function::Call                    💥 EXC_BAD_ACCESS (x9 = 0x0)

Omitting params, passing {}, or reportProgress: false all avoid the crash because they don't emit progress notifications mid-generation.

Approach

Treat the channel as a deferred transport: send() never re-enters JavaScript, it only queues the (already converted) message. Delivery happens via flush() at the two points where re-entering JS is provably safe:

  1. After dispatchProtocolMessage() in js_inspector_s::send(): responses to a client request are delivered synchronously, preserving the existing request/response behaviour (no observable change; existing tests untouched).
  2. At the end of js_env_s::run_macrotasks() — notifications emitted from a V8 task (heap snapshot progress/chunks) are delivered between macrotasks.

takeHeapSnapshot schedules the snapshot as a task, so its messages aren't in the queue at point (1) and are delivered at point (2), out of the forbidden window.

Note on flushProtocolNotifications(): V8's own hook is left as a no-op on purpose. V8 calls it from HeapSnapshotProgress::ReportProgressValue so delivering there would re-crash.

Ref: https://gist.github.com/vietthang/3fa883343ff10a2ea4cf2a9b6a9e5b5b

tony-go added 6 commits July 20, 2026 18:11
Signed-off-by: Tony Gorez <gorez.tony@gmail.com>
Signed-off-by: Tony Gorez <gorez.tony@gmail.com>
Signed-off-by: Tony Gorez <gorez.tony@gmail.com>
Signed-off-by: Tony Gorez <gorez.tony@gmail.com>
Signed-off-by: Tony Gorez <gorez.tony@gmail.com>
Signed-off-by: Tony Gorez <gorez.tony@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant