Skip to content

Fix use-after-free in CreateDefaultDisplayReporter (#2240)#2265

Open
devtejasx wants to merge 1 commit into
google:mainfrom
devtejasx:fix-default-display-reporter-uaf
Open

Fix use-after-free in CreateDefaultDisplayReporter (#2240)#2265
devtejasx wants to merge 1 commit into
google:mainfrom
devtejasx:fix-default-display-reporter-uaf

Conversation

@devtejasx

Copy link
Copy Markdown
Contributor

Fixes #2240.

CreateDefaultDisplayReporter() transfers ownership of the returned reporter to
the caller: it calls .release(), and RunSpecifiedBenchmarks() wraps the
result in a unique_ptr that deletes it on return. The implementation, however,
cached that owning pointer in a function-local static. After the first
RunSpecifiedBenchmarks() call deleted the reporter, a subsequent call returned
the same, now-dangling pointer, causing a heap-use-after-free in
BenchmarkReporter::GetOutputStream().

This removes the static so each call returns a fresh, caller-owned reporter,
matching the function's name and its .release() contract.

Note: I'm aware the reproducer relied on calling RunSpecifiedBenchmarks() more
than once, which isn't the primary intended usage. The change here is really an
ownership fix -- a Create* function that hands ownership to the caller should
not also cache that pointer -- and it makes repeated calls safe as a side
effect. Happy to drop the regression test if you'd rather not codify multi-call
behavior.

Verification

  • Deterministic before/after: the old code returns the same cached pointer on
    two successive calls (the one the caller has already deleted); the new code
    returns two distinct, independently-owned reporters.
  • Added create_default_display_reporter_gtest asserting successive calls return
    distinct reporters; full build passes.

Per AGENTS.md: AI-assisted — the patch was drafted with AI assistance
(Claude) and then reviewed, tested, and understood by me. I take full
responsibility for it.

CreateDefaultDisplayReporter() transfers ownership of the returned
reporter to the caller: it calls .release() and RunSpecifiedBenchmarks()
wraps the result in a unique_ptr that deletes it on return.

The implementation, however, cached that owning pointer in a
function-local static. After the first RunSpecifiedBenchmarks() call
deleted the reporter, the second call returned the same, now-dangling
pointer, causing a heap-use-after-free in
BenchmarkReporter::GetOutputStream().

Create a fresh reporter on every call so each caller owns and deletes an
independent object. Add a regression test asserting successive calls
return distinct, individually-owned reporters.

AI-assisted: patch drafted with AI assistance (Claude); reviewed,
tested, and understood by me. I take full responsibility for it.
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.

[BUG]Heap-use-after-free in benchmark `RunSpecifiedBenchmarks

1 participant