From a8d1f08bd8a0d0bf1816af568949ec79628b73f0 Mon Sep 17 00:00:00 2001 From: Dhruv Chawla Date: Wed, 11 Feb 2026 10:22:18 +0000 Subject: [PATCH 1/2] Fix dangling pointer bug in AutoFDOProfileReader::ReadNameTable The gcov_read_string function (https://github.com/google/autofdo/blob/master/gcov.cc#L226) returns a raw pointer to an internal buffer that can be realloc'd if it is too small (https://github.com/google/autofdo/blob/master/gcov.cc#L182-L184): ```cpp static inline void gcov_allocate(unsigned byte_length) { ... gcov_var.buffer = static_cast(realloc(gcov_var.buffer, new_byte_size)); } ... static inline const char *gcov_read_bytes(unsigned bytes) { const char *result; unsigned excess_bytes = gcov_var.byte_length - gcov_var.byte_offset; ... if (excess_bytes < bytes) { ... if (gcov_var.byte_length + bytes > gcov_var.byte_alloc) { gcov_allocate(gcov_var.byte_length + bytes); } ... } ... } const char * gcov_read_string(void) { ... if (absl::GetFlag(FLAGS_gcov_version) >= 2) { return gcov_read_bytes (length); } ... } ``` This means that the pointer that is returned can be invalidated by the very next read from the buffer, as seemed to be happening here. When I was stepping through this in a debugger, the string that was read magically got turned into an empty string after the next read. --- profile_reader.cc | 2 +- profile_writer.cc | 8 ++++++-- symbol_map.h | 3 ++- 3 files changed, 9 insertions(+), 4 deletions(-) diff --git a/profile_reader.cc b/profile_reader.cc index 745e95d..b989cd0 100644 --- a/profile_reader.cc +++ b/profile_reader.cc @@ -132,7 +132,7 @@ void AutoFDOProfileReader::ReadNameTable() { } uint32_t name_vector_size = gcov_read_unsigned(); for (uint32_t i = 0; i < name_vector_size; i++) { - const char *name = gcov_read_string(); + const char *name = strdup(gcov_read_string()); uint32_t file_index = absl::GetFlag(FLAGS_gcov_version) >= 3 ? gcov_read_unsigned() : -1; names_.emplace_back(name, file_index); diff --git a/profile_writer.cc b/profile_writer.cc index 8482642..0c5fe86 100644 --- a/profile_writer.cc +++ b/profile_writer.cc @@ -124,13 +124,17 @@ class SourceProfileWriter: public SymbolTraverser { virtual void VisitTopSymbol(const std::string &name, const Symbol *node) { gcov_write_counter(node->head_count); - gcov_write_unsigned(GetStringIndex(Symbol::Name(name.c_str()))); + unsigned NameIdx = GetStringIndex(Symbol::Name(name.c_str())); + CHECK(NameIdx != 0 && "name index 0 should never be present as a top-level symbol!"); + gcov_write_unsigned(NameIdx); } virtual void VisitCallsite(const Callsite &callsite) { uint64_t value = callsite.location; gcov_write_unsigned(SourceInfo::GenerateCompressedOffset(value)); - gcov_write_unsigned(GetStringIndex(Symbol::Name(callsite.callee_name))); + unsigned NameIdx = GetStringIndex(Symbol::Name(callsite.callee_name)); + CHECK(NameIdx != 0 && "name index 0 should never be present as a callee!"); + gcov_write_unsigned(NameIdx); } private: diff --git a/symbol_map.h b/symbol_map.h index 9e47211..008d21f 100644 --- a/symbol_map.h +++ b/symbol_map.h @@ -177,7 +177,8 @@ class Symbol { ~Symbol(); static std::string Name(const char *name) { - return (name && strlen(name) > 0) ? name : "noname"; + CHECK(strlen(name) > 0 && "Empty string should never occur in profile!"); + return name ? name : "noname"; } std::string name() const { return Name(info.func_name); } From b277927c314753d1dced92f0e02661979564c26d Mon Sep 17 00:00:00 2001 From: Dhruv Chawla Date: Fri, 27 Feb 2026 00:42:42 -0800 Subject: [PATCH 2/2] Address review comments --- profile_reader.cc | 2 +- symbol_map.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/profile_reader.cc b/profile_reader.cc index b989cd0..3f198d2 100644 --- a/profile_reader.cc +++ b/profile_reader.cc @@ -132,7 +132,7 @@ void AutoFDOProfileReader::ReadNameTable() { } uint32_t name_vector_size = gcov_read_unsigned(); for (uint32_t i = 0; i < name_vector_size; i++) { - const char *name = strdup(gcov_read_string()); + std::string name = gcov_read_string(); uint32_t file_index = absl::GetFlag(FLAGS_gcov_version) >= 3 ? gcov_read_unsigned() : -1; names_.emplace_back(name, file_index); diff --git a/symbol_map.h b/symbol_map.h index 008d21f..b9c56df 100644 --- a/symbol_map.h +++ b/symbol_map.h @@ -177,8 +177,8 @@ class Symbol { ~Symbol(); static std::string Name(const char *name) { - CHECK(strlen(name) > 0 && "Empty string should never occur in profile!"); - return name ? name : "noname"; + CHECK(name && strlen(name) > 0 && "Empty string should never occur in profile!"); + return name; } std::string name() const { return Name(info.func_name); }