From 6d6061eaaee2699bd79be813bfd59350e6220881 Mon Sep 17 00:00:00 2001 From: leftibot Date: Sat, 2 May 2026 11:29:52 -0600 Subject: [PATCH] Fix #141: skip leak sanitizer on Apple platforms LeakSanitizer is unsupported on macOS (clang rejects -fsanitize=leak on arm64-apple-darwin and other Apple targets); leak detection there is provided by AddressSanitizer with ASAN_OPTIONS=detect_leaks=1. When myproject_ENABLE_SANITIZER_LEAK is requested on an Apple host, myproject_enable_sanitizers now warns and drops it from the sanitizer list instead of producing an unsupported -fsanitize=leak compile flag. Adds two CMake-script regression tests that stub target_*_options to verify leak is filtered out on Apple and still propagated elsewhere. --- cmake/Sanitizers.cmake | 9 ++- test/CMakeLists.txt | 10 +++ .../test_sanitizers_apple_excludes_leak.cmake | 62 +++++++++++++++++++ ...t_sanitizers_non_apple_includes_leak.cmake | 52 ++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 test/cmake/test_sanitizers_apple_excludes_leak.cmake create mode 100644 test/cmake/test_sanitizers_non_apple_includes_leak.cmake diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake index e238fa21..06017fe1 100644 --- a/cmake/Sanitizers.cmake +++ b/cmake/Sanitizers.cmake @@ -15,7 +15,14 @@ function( endif() if(${ENABLE_SANITIZER_LEAK}) - list(APPEND SANITIZERS "leak") + # LeakSanitizer is unsupported on Apple platforms (the linker rejects + # -fsanitize=leak on macOS, including arm64). On Apple, leak detection + # is provided by AddressSanitizer with ASAN_OPTIONS=detect_leaks=1. + if(APPLE) + message(WARNING "Leak sanitizer is not supported on Apple platforms; ignoring myproject_ENABLE_SANITIZER_LEAK") + else() + list(APPEND SANITIZERS "leak") + endif() endif() if(${ENABLE_SANITIZER_UNDEFINED_BEHAVIOR}) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8679286f..bea3498f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,16 @@ include(${Catch2_SOURCE_DIR}/extras/Catch.cmake) # Provide a simple smoke test to make sure that the CLI works and can display a --help message add_test(NAME cli.has_help COMMAND intro --help) +# CMake-script regression tests for cmake/Sanitizers.cmake (issue #141). +add_test( + NAME cmake.sanitizers.apple_excludes_leak + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/test_sanitizers_apple_excludes_leak.cmake) +add_test( + NAME cmake.sanitizers.non_apple_includes_leak + COMMAND ${CMAKE_COMMAND} -P + ${CMAKE_CURRENT_SOURCE_DIR}/cmake/test_sanitizers_non_apple_includes_leak.cmake) + # Provide a test to verify that the version being reported from the application # matches the version given to CMake. This will be important once you package # your program. Real world shows that this is the kind of simple mistake that is easy diff --git a/test/cmake/test_sanitizers_apple_excludes_leak.cmake b/test/cmake/test_sanitizers_apple_excludes_leak.cmake new file mode 100644 index 00000000..1d58b861 --- /dev/null +++ b/test/cmake/test_sanitizers_apple_excludes_leak.cmake @@ -0,0 +1,62 @@ +# Regression test for #141: macOS ARM doesn't support leak sanitizer. +# +# Simulates an Apple toolchain by setting APPLE=TRUE before including +# Sanitizers.cmake, stubs the target_*_options commands so that the flags +# requested by myproject_enable_sanitizers can be inspected, then asserts +# that "leak" is not propagated to the compiler/linker even when the user +# enables the leak sanitizer option. + +cmake_minimum_required(VERSION 3.21) + +set(APPLE TRUE) +set(MSVC FALSE) +set(CMAKE_CXX_COMPILER_ID "Clang") + +set_property(GLOBAL PROPERTY captured_compile_options "") +set_property(GLOBAL PROPERTY captured_link_options "") + +function(target_compile_options) + set_property(GLOBAL PROPERTY captured_compile_options "${ARGN}") +endfunction() + +function(target_link_options) + set_property(GLOBAL PROPERTY captured_link_options "${ARGN}") +endfunction() + +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/Sanitizers.cmake") + +myproject_enable_sanitizers( + test_target + ON # ENABLE_SANITIZER_ADDRESS + ON # ENABLE_SANITIZER_LEAK (should be filtered out on Apple) + OFF # ENABLE_SANITIZER_UNDEFINED_BEHAVIOR + OFF # ENABLE_SANITIZER_THREAD + OFF # ENABLE_SANITIZER_MEMORY +) + +get_property(compile_options GLOBAL PROPERTY captured_compile_options) +get_property(link_options GLOBAL PROPERTY captured_link_options) + +message(STATUS "Captured compile options: ${compile_options}") +message(STATUS "Captured link options: ${link_options}") + +if(compile_options MATCHES "leak") + message( + FATAL_ERROR + "Leak sanitizer must not be enabled on Apple platforms (#141), " + "but compile options contain 'leak': ${compile_options}") +endif() + +if(link_options MATCHES "leak") + message( + FATAL_ERROR + "Leak sanitizer must not be enabled on Apple platforms (#141), " + "but link options contain 'leak': ${link_options}") +endif() + +if(NOT compile_options MATCHES "address") + message( + FATAL_ERROR + "Address sanitizer should still be enabled when leak is filtered out, " + "but compile options were: ${compile_options}") +endif() diff --git a/test/cmake/test_sanitizers_non_apple_includes_leak.cmake b/test/cmake/test_sanitizers_non_apple_includes_leak.cmake new file mode 100644 index 00000000..11ade545 --- /dev/null +++ b/test/cmake/test_sanitizers_non_apple_includes_leak.cmake @@ -0,0 +1,52 @@ +# Companion to test_sanitizers_apple_excludes_leak.cmake (#141). +# Verifies that on non-Apple platforms the leak sanitizer is still +# propagated to the compiler/linker, so the Apple-specific guard does +# not silently disable leak detection elsewhere. + +cmake_minimum_required(VERSION 3.21) + +set(APPLE FALSE) +set(MSVC FALSE) +set(CMAKE_CXX_COMPILER_ID "Clang") + +set_property(GLOBAL PROPERTY captured_compile_options "") +set_property(GLOBAL PROPERTY captured_link_options "") + +function(target_compile_options) + set_property(GLOBAL PROPERTY captured_compile_options "${ARGN}") +endfunction() + +function(target_link_options) + set_property(GLOBAL PROPERTY captured_link_options "${ARGN}") +endfunction() + +include("${CMAKE_CURRENT_LIST_DIR}/../../cmake/Sanitizers.cmake") + +myproject_enable_sanitizers( + test_target + OFF # ENABLE_SANITIZER_ADDRESS + ON # ENABLE_SANITIZER_LEAK + OFF # ENABLE_SANITIZER_UNDEFINED_BEHAVIOR + OFF # ENABLE_SANITIZER_THREAD + OFF # ENABLE_SANITIZER_MEMORY +) + +get_property(compile_options GLOBAL PROPERTY captured_compile_options) +get_property(link_options GLOBAL PROPERTY captured_link_options) + +message(STATUS "Captured compile options: ${compile_options}") +message(STATUS "Captured link options: ${link_options}") + +if(NOT compile_options MATCHES "leak") + message( + FATAL_ERROR + "Leak sanitizer must still be enabled on non-Apple platforms, " + "but compile options were: ${compile_options}") +endif() + +if(NOT link_options MATCHES "leak") + message( + FATAL_ERROR + "Leak sanitizer must still be enabled on non-Apple platforms, " + "but link options were: ${link_options}") +endif()