rust bindings: keep argv[0] alive across benchmark reporting (#2237)
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.
diff --git a/bindings/rust/src/rust_api.cc b/bindings/rust/src/rust_api.cc
index 5efc5fa..c85997e 100644
--- a/bindings/rust/src/rust_api.cc
+++ b/bindings/rust/src/rust_api.cc
@@ -15,7 +15,14 @@
}
void Initialize(int* argc, size_t argv) {
- ::benchmark::Initialize(argc, (char**)argv);
+ char** argv_ptr = reinterpret_cast<char**>(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) {