I am linking a shared library that defines a global variable like so:
__attribute__((visibility("hidden"))) extern HookList<MallocHook::DeleteHook> delete_hooks_;
However, it looks like it is duplicated despite being declared as extern
. With 2 different stack traces the addresses of delete_hooks_
are different. Compare:
this == 0x5574f1215968
base::internal::HookList<void (*)(const void *)>::Add(void (*)(const void *)) malloc_hook.cc:155
::MallocHook_AddDeleteHook(MallocHook_DeleteHook) malloc_hook.cc:265
MallocHook::AddDeleteHook(void (*)(const void *)) malloc_hook.h:115
::HeapProfilerStart(const char *) heap-profiler.cc:454
main main.cpp:5
this == 0x7efe998baa28
base::internal::HookList<void (*)(const void *)>::empty() const malloc_hook-inl.h:88
[Inlined] free_fast_path(void *) tcmalloc.cc:1944
::tc_free(void *) tcmalloc.cc:1953
main main.cpp:6
My questions:
- Why is the variable duplicated? Isn’t the
extern
keyword supposed to prevent it from happening? - How can this duplication be avoided?
- Am I misusing the library? I believe I have followed the instructions precisely. See https://gperftools.github.io/gperftools/heapprofile.html
Complete example and other important bits of information:
- I am using LLVM toolchain 19.0.0 on Ubuntu 20.04.
- Additional cmake flags are
-DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=/usr/bin/clang-19 -DCMAKE_CXX_COMPILER=/usr/bin/clang++-19
- I am using gperftools 2.15 from https://github.com/gperftools/gperftools
# CMakeLists.txt
cmake_minimum_required(VERSION 3.28) # likely compatible with an older version too
project(Example LANGUAGES CXX)
add_executable(Example main.cpp)
set(gperftools_build_benchmark OFF CACHE BOOL "Build gperftools benchmark" FORCE)
set(PATH_TO_GPERFTOOLS "${CMAKE_SOURCE_DIR}/gperftools")
add_subdirectory(${PATH_TO_GPERFTOOLS})
target_link_libraries(Example tcmalloc)
target_include_directories(Example PRIVATE ${PATH_TO_GPERFTOOLS}/src)
// main.cpp
#include <cstdlib>
#include "gperftools/heap-profiler.h"
int main() {
HeapProfilerStart("/tmp/example");
std::free(nullptr);
HeapProfilerStop();
return 0;
}