From 9a4268f12678b49de604dd59e7888089b93708d5 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Mon, 21 Oct 2024 02:51:18 +0100 Subject: [PATCH 1/2] Fix symbol resolution for malloc_type functions on macOS Sequoia This commit addresses an issue with symbol resolution for malloc_type functions on the latest macOS Sequoia. The problem arises due to changes in how these functions are named in the dynamic symbol table of the system libraries that are part of the linker cache like the ones that contain the C++ runtime. This fix ensures that Memray correctly intercepts and tracks allocations made by malloc_type functions, fixing tracking allocations in the C++ runtime and other system libraries on macOS Sequoia. Signed-off-by: Pablo Galindo --- src/memray/_memray/macho_shenanigans.cpp | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/memray/_memray/macho_shenanigans.cpp b/src/memray/_memray/macho_shenanigans.cpp index fc310eb831..d725b453d3 100644 --- a/src/memray/_memray/macho_shenanigans.cpp +++ b/src/memray/_memray/macho_shenanigans.cpp @@ -36,6 +36,19 @@ patch_symbol( } } +static inline const char* +get_canonical_name(const char* name) +{ + // In macOS 15 (Sequoia)+, the symbols in the shared cache have a prefix + // "_malloc_type" that we need to remove to match the symbols that we + // are looking for. + const char* prefix = "_malloc_type"; + if (strncmp(name, prefix, strlen(prefix)) != 0) { + return name; + } + return name + strlen(prefix); +} + static void patch_symbols_in_section( const section_t* section, @@ -49,8 +62,9 @@ patch_symbols_in_section( if (!symbol_name || !(symbol_name[0] == '_' || symbol_name[0] == '.') || !symbol_name[1]) { continue; } + const char* canonical_name = get_canonical_name(symbol_name); #define FOR_EACH_HOOKED_FUNCTION(hookname) \ - if (strcmp(MEMRAY_ORIG(hookname).d_symbol, symbol_name + 1) == 0) { \ + if (strcmp(MEMRAY_ORIG(hookname).d_symbol, canonical_name + 1) == 0) { \ LOG(DEBUG) << "Patching " << symbol_name << " symbol pointer at " << std::hex << std::showbase \ << *(symbol_addr_table + i) << " for relocation entry " << (symbol_addr_table + i); \ patch_symbol( \ @@ -225,9 +239,10 @@ patch_stubs( if (!symbol_name || !(symbol_name[0] == '_' || symbol_name[0] == '.') || !symbol_name[1]) { continue; } + const char* canonical_name = get_canonical_name(symbol_name); auto stub_addr = reinterpret_cast(symbol_addr_table + i * element_size); #define FOR_EACH_HOOKED_FUNCTION(hookname) \ - if (strcmp(MEMRAY_ORIG(hookname).d_symbol, symbol_name + 1) == 0) { \ + if (strcmp(MEMRAY_ORIG(hookname).d_symbol, canonical_name + 1) == 0) { \ LOG(DEBUG) << "Extracting symbol address for " << symbol_name << " from stub function at " \ << std::hex << std::showbase << stub_addr; \ void* symbol_addr = reinterpret_cast(lazy_pointer_from_stub(stub_addr)); \ From 1a8d38d516a2101b32472b70cb850e8ca56c92d9 Mon Sep 17 00:00:00 2001 From: Pablo Galindo Date: Wed, 23 Oct 2024 17:56:32 +0100 Subject: [PATCH 2/2] Skip coverage html generation in Alpine There a bug either in the genhtml utility in Alpine or in coverage.py that trips over some categories that are in the dump file. We don't use these files in CI for anything so for now we should skip the html generation. Signed-off-by: Pablo Galindo --- .github/workflows/build.yml | 3 +++ Makefile | 4 +++- news/693.bugfix.rst | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 news/693.bugfix.rst diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4484668b8a..77852d06d4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,6 +72,9 @@ jobs: container: image: alpine options: --cap-add=SYS_PTRACE + env: + # Coverage is kind of broken in Alpine + SKIP_COVERAGE_HTML: 1 steps: - uses: actions/checkout@v4 - name: Set up dependencies diff --git a/Makefile b/Makefile index 96d141e917..18ff5226c4 100644 --- a/Makefile +++ b/Makefile @@ -78,7 +78,9 @@ pycoverage: ## Run the test suite, with Python code coverage --cov-append $(PYTEST_ARGS) \ tests $(PYTHON) -m coverage lcov -i -o pycoverage.lcov - genhtml *coverage.lcov --branch-coverage --output-directory memray-coverage $(GENHTMLOPTS) + if [ -z "$$SKIP_COVERAGE_HTML" ]; then \ + genhtml *coverage.lcov --branch-coverage --output-directory memray-coverage $(GENHTMLOPTS); \ + fi .PHONY: valgrind valgrind: ## Run valgrind, with the correct configuration diff --git a/news/693.bugfix.rst b/news/693.bugfix.rst new file mode 100644 index 0000000000..2957757b92 --- /dev/null +++ b/news/693.bugfix.rst @@ -0,0 +1 @@ +Fixed a bug that was causing tracking of runtime libraries that are part of the linker cache not work in macOS 15.