From 554f230498020e6a4f4e0488d0fcf7f4cc97897d Mon Sep 17 00:00:00 2001 From: Siddharth Tiwari Date: Tue, 30 Jun 2026 22:38:30 +0530 Subject: [PATCH] rust bindings: keep argv[0] alive across benchmark reporting The Rust binding's initialize() creates temporary CString buffers that are freed on return, but benchmark::Initialize() stores argv[0] as a raw pointer in BenchmarkReporter::Context::executable_name. Later reporter calls dereference freed heap memory (use-after-free). Copy argv[0] into static storage in the C++ bridge before calling benchmark::Initialize(), ensuring the retained pointer remains valid for the process lifetime. AI assistance disclosure: AI tooling was used to assist with auditing, reproducer design, patch drafting, and PR text preparation. --- bindings/rust/src/rust_api.cc | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/bindings/rust/src/rust_api.cc b/bindings/rust/src/rust_api.cc index 5efc5fac69..c85997e390 100644 --- a/bindings/rust/src/rust_api.cc +++ b/bindings/rust/src/rust_api.cc @@ -15,7 +15,14 @@ void RegisterBenchmark(rust::Str name, rust::Fn func) { } void Initialize(int* argc, size_t argv) { - ::benchmark::Initialize(argc, (char**)argv); + char** argv_ptr = reinterpret_cast(argv); + if (argc != nullptr && *argc > 0 && argv_ptr != nullptr && + argv_ptr[0] != nullptr) { + static std::string executable_name; + executable_name = argv_ptr[0]; + argv_ptr[0] = executable_name.data(); + } + ::benchmark::Initialize(argc, argv_ptr); } void SkipWithError(benchmark::State& state, rust::Str msg) {