From 90decd4eaf308fd219033c88c9af5208ff820565 Mon Sep 17 00:00:00 2001 From: "trop[bot]" <37223003+trop[bot]@users.noreply.github.com> Date: Tue, 31 Mar 2026 10:15:13 +0200 Subject: [PATCH] fix: add missing HandleScope in contentTracing.getTraceBufferUsage() (#50594) The `OnTraceBufferUsageAvailable` callback creates V8 handles via `Dictionary::CreateEmpty()` before `promise.Resolve()` enters its `SettleScope` (which provides a `HandleScope`). When the callback fires asynchronously from a Mojo response (i.e. when a trace session is active), there is no `HandleScope` on the stack, causing a fatal V8 error: "Cannot create a handle without a HandleScope". Add an explicit `v8::HandleScope` at the top of the callback, matching the pattern used by the other contentTracing APIs which resolve their promises through `SettleScope` or the static `ResolvePromise` helper. Made-with: Cursor Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Alexey Kozy --- .../api/electron_api_content_tracing.cc | 5 +++- spec/api-content-tracing-spec.ts | 30 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/shell/browser/api/electron_api_content_tracing.cc b/shell/browser/api/electron_api_content_tracing.cc index 6eaf1c69c1..8b19e08f26 100644 --- a/shell/browser/api/electron_api_content_tracing.cc +++ b/shell/browser/api/electron_api_content_tracing.cc @@ -151,7 +151,10 @@ void OnTraceBufferUsageAvailable( gin_helper::Promise promise, float percent_full, size_t approximate_count) { - auto dict = gin_helper::Dictionary::CreateEmpty(promise.isolate()); + v8::Isolate* isolate = promise.isolate(); + v8::HandleScope handle_scope(isolate); + + auto dict = gin_helper::Dictionary::CreateEmpty(isolate); dict.Set("percentage", percent_full); dict.Set("value", approximate_count); diff --git a/spec/api-content-tracing-spec.ts b/spec/api-content-tracing-spec.ts index 102d5e3697..c18edaf348 100644 --- a/spec/api-content-tracing-spec.ts +++ b/spec/api-content-tracing-spec.ts @@ -132,6 +132,36 @@ ifdescribe(!(['arm', 'arm64'].includes(process.arch)) || (process.platform !== ' }); }); + describe('getTraceBufferUsage', function () { + this.timeout(10e3); + + it('does not crash and returns valid usage data', async () => { + await app.whenReady(); + await contentTracing.startRecording({ + categoryFilter: '*', + traceOptions: 'record-until-full' + }); + + // Yield to the event loop so the JS HandleScope from this tick is gone. + // When the Mojo response arrives it fires OnTraceBufferUsageAvailable + // as a plain Chromium task — if that callback lacks its own HandleScope + // the process will crash with "Cannot create a handle without a HandleScope". + const result = await contentTracing.getTraceBufferUsage(); + + expect(result).to.have.property('percentage').that.is.a('number'); + expect(result).to.have.property('value').that.is.a('number'); + + await contentTracing.stopRecording(); + }); + + it('returns zero usage when no trace is active', async () => { + await app.whenReady(); + const result = await contentTracing.getTraceBufferUsage(); + expect(result).to.have.property('percentage').that.is.a('number'); + expect(result.percentage).to.equal(0); + }); + }); + describe('captured events', () => { it('include V8 samples from the main process', async function () { this.timeout(60000);