Skip to content

Fix dispose and getContext data race - #6327

Merged
inancgumus merged 4 commits into
grafana:masterfrom
JohnPei1:fix-browser-context-race
Sep 16, 2026
Merged

inancgumus merged 4 commits into
grafana:masterfrom
JohnPei1:fix-browser-context-race

Conversation

@JohnPei1

@JohnPei1 JohnPei1 commented Aug 23, 2026 •

Copy link
Copy Markdown
Contributor

What?

Fixes a data race between BrowserContext.Close() and BrowserContext.NewPage().

Added read lock to the context getter Context() , and updated read accesses to the browser context to use the getter .

Adds a regression test that runs context disposal and context lookup concurrently

Why?

BrowserContext.Close() sets b.context = nil without acquiring any lock, which causes getDefaultBrowserContextOrMatchedID() to return a nil b.context when interleaved in a certain way.

The new test, when ran with go test -race ./internal/js/modules/k6/browser/common before the fix, shows the data race
image

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

Checklist: Documentation (only for k6 maintainers and if relevant)

Please do not merge this PR until the following items are filled out.

  • I have added the correct milestone and labels to the PR.
  • I have updated the release notes: link
  • I have updated or added an issue to the k6-documentation: grafana/k6-docs#NUMBER if applicable
  • I have updated or added an issue to the TypeScript definitions: grafana/k6-DefinitelyTyped#NUMBER if applicable

Related PR(s)/Issue(s)

Closes #5328

@JohnPei1
JohnPei1 requested a review from a team as a code owner August 23, 2026 01:28
@JohnPei1
JohnPei1 requested review from ankur22 and mstoykov and removed request for a team August 23, 2026 01:28
@github-actions

github-actions Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

Signed commits report

All 4 commits between master and fix-browser-context-race have verified signatures. โœ…

@cla-assistant

cla-assistant Bot commented Aug 23, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@JohnPei1 JohnPei1 changed the title Fix dispose and getContext data race. Closes #5328 Fix dispose and getContext data race Aug 23, 2026
@JohnPei1
JohnPei1 force-pushed the fix-browser-context-race branch from 44a8ae0 to eaf0acb Compare August 23, 2026 02:39

@ankur22 ankur22 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we update the contextMu comment as part of this? It currently says the mutex protects only the NewContext/getDefaultBrowserContextOrMatchedID edge case and โ€œthis one case,โ€ but disposeContext now relies on it too. That no longer describes the locking invariant.

if err := action.Do(cdp.WithExecutor(b.vuCtx, b.conn)); err != nil {
return fmt.Errorf("disposing browser context ID %s: %w", id, err)
}
b.contextMu.Lock()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This synchronizes the write with getDefaultBrowserContextOrMatchedID, but Browser.Context() still returns b.context without the mutex; CloseContext() and NewContext() also read it directly. Since browser.context() is synchronous while closeContext() runs in a promise goroutine, the disposal write can still race with those reads. Could we route every access to b.context through contextMu and cover the public getter in the regression test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated all context read accesses to route through the Context() getter and added read lock to the getter. This should fix the race between the disposal write and context reads.

However, one concern is that methods like CloseContext() and NewContext() still operate on a snapshot of the current context after releasing contextMu. And it could lead to undesirable results like Close() being called on a disposed context. I wonder if we should add a new mutex to serialize all close/create operations, and whether we should open a separate ticket for that purpose.

go func() {
defer wg.Done()
for range iterations {
_ = b.disposeContext(browserContextID)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we add assertions for the operation results here? At the moment the dispose error and lookup result are both discarded, so without -race this only proves that the goroutines finished. Iโ€™d collect the results and, after wg.Wait(), verify that disposal succeeded, every lookup returned a non-nil context, and the final context is nil/default. A NotPanics wrapper wouldnโ€™t catch panics from these worker goroutines; an unrecovered panic already fails the test anyway.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call. Expanded the regression test to assert return values and states, also included the public getter in the test and updated the stale comment on contextMu.

@JohnPei1
JohnPei1 requested a review from ankur22 September 7, 2026 01:10
@JohnPei1
JohnPei1 temporarily deployed to azure-trusted-signing September 10, 2026 13:53 — with GitHub Actions Inactive
@JohnPei1
JohnPei1 temporarily deployed to azure-trusted-signing September 10, 2026 13:55 — with GitHub Actions Inactive
@AgnesToulet
AgnesToulet force-pushed the fix-browser-context-race branch from 953206e to 3d2324f Compare September 15, 2026 12:13
@AgnesToulet
AgnesToulet temporarily deployed to azure-trusted-signing September 15, 2026 12:19 — with GitHub Actions Inactive
@AgnesToulet
AgnesToulet temporarily deployed to azure-trusted-signing September 15, 2026 12:21 — with GitHub Actions Inactive
@AgnesToulet

Copy link
Copy Markdown
Contributor

@JohnPei1 Can you sign all your commits so we can get this PR merged please? Sorry if it was the case before, I may have lost the signature when I rebased your PR to get the CI to pass.

@JohnPei1
JohnPei1 force-pushed the fix-browser-context-race branch from 3d2324f to 6749c62 Compare September 16, 2026 00:32
@JohnPei1

Copy link
Copy Markdown
Contributor Author

@JohnPei1 Can you sign all your commits so we can get this PR merged please? Sorry if it was the case before, I may have lost the signature when I rebased your PR to get the CI to pass.

No worries, should (hopefully) be good now!

@mstoykov mstoykov added this to the v2.3.0 milestone Sep 16, 2026
@JohnPei1
JohnPei1 temporarily deployed to azure-trusted-signing September 16, 2026 07:25 — with GitHub Actions Inactive
@JohnPei1
JohnPei1 temporarily deployed to azure-trusted-signing September 16, 2026 07:27 — with GitHub Actions Inactive
@inancgumus
inancgumus merged commit 01d3c93 into grafana:master Sep 16, 2026
61 of 63 checks passed

This branch was previously deployed

1 inactive deployment
azure-trusted-signing โ€” 6749c621 Deployed Sep 16, 2026 by JohnPei1 via sign-packages #10703
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.

BrowserContext.NewPage may be racing with BrowserContext.Close

5 participants