0

I'm trying to write CMake tests to detect leaks using the leaks command line tool that comes with XCode on macOS. I've been using LSAN with the Homebrew install of LLVM, but the run times on my M1 are 100x more than what they are on an amd64 machine.

Here's an example C source file with a memory leak:

// memory-leak.c
#include <stdlib.h>
void *p;
int main()
{
    p = malloc(7);
    p = 0; // The memory is leaked here.
    return 0;
}

After compiling with clang memory-leak.c -o memleak and running the leaks command leaks -quiet -atExit -- ./memleak, the output is

% leaks -quiet -atExit -- ./memleak
Process 22773 is not debuggable. Due to security restrictions, leaks can only show or save contents of readonly memory of restricted processes.

leaks Report Version: 4.0
Process 22773: 214 nodes malloced for 12 KB
Process 22773: 1 leak for 16 total leaked bytes.

    1 (16 bytes) ROOT LEAK: 0x600002970050 [16]

I want to include this process as CMake test targets. The CMakeLists.txt file is:

#CMakeLists.txt
cmake_minimum_required(VERSION 3.18)

project(memleak)

find_program(LEAKS_PATH NAMES leaks REQUIRED True)

enable_testing()
add_executable(memleak memory-leak.c)
add_test(NAME memleak COMMAND leaks -quiet -atExit -- $<TARGET_FILE:memleak>)
set_tests_properties(memleak PROPERTIES WILL_FAIL True)

The resulting test hangs indefinitely. Here's the terminal command and output.

% mkdir build && cd build && cmake .. && cmake --build . && ctest --verbose
-- The C compiler identification is AppleClang 13.1.6.13160021
-- The CXX compiler identification is AppleClang 13.1.6.13160021
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/user/leakstest/build
[ 50%] Building C object CMakeFiles/memleak.dir/memory-leak.c.o
[100%] Linking C executable memleak
[100%] Built target memleak
UpdateCTestConfiguration  from :/Users/user/leakstest/build/DartConfiguration.tcl
UpdateCTestConfiguration  from :/Users/user/leakstest/build/DartConfiguration.tcl
Test project /Users/user/leakstest/build
Constructing a list of tests
Done constructing a list of tests
Updating test list for fixtures
Added 0 tests to meet fixture requirements
Checking test dependency graph...
Checking test dependency graph end
test 1
    Start 1: memleak

1: Test command: /usr/bin/leaks "-atExit" "--" "/Users/user/leakstest/build/memleak"
1: Test timeout computed to be: 10000000
1: Process 24942 is not debuggable. Due to security restrictions, leaks can only show or save contents of readonly memory of restricted processes.
1: 
1: Process:         memleak [24942]
1: Path:            /Users/USER/*/memleak
1: Load Address:    0x100208000
1: Identifier:      memleak
1: Version:         ???
1: Code Type:       ARM64
1: Platform:        macOS
1: Parent Process:  leaks [24941]
1: 
1: Date/Time:       2022-05-17 18:38:15.553 -0500
1: Launch Time:     2022-05-17 18:38:15.282 -0500
1: OS Version:      macOS 12.3.1 (21E258)
1: Report Version:  7
1: Analysis Tool:   /Applications/Xcode.app/Contents/Developer/usr/bin/leaks
1: Analysis Tool Version:  Xcode 13.3 (13E113)
1: 
1: Physical footprint:         7233K
1: Physical footprint (peak):  7233K
1: ----
1: 
1: leaks Report Version: 4.0
1: Process 24942: 214 nodes malloced for 12 KB
1: Process 24942: 1 leak for 16 total leaked bytes.
1: 
1:     1 (16 bytes) ROOT LEAK: 0x600002840050 [16]
1: 

The test never exits. I expect the test to pass since there's a memory leak and the CMake file specifies that the test will fail.

The output of build/ctest --verbose shows that leaks is picking up on the memory leak, but it seems that CTest isn't responding to leaks returning.

I've tried using a shell script that contains exec leaks -quiet -atExit -- "$@" in place of the command, but I get the same results.

I've also tried doing the same thing with a Meson build file and got the same result.

Is there something I'm missing?

mmdski
  • 96
  • 5
  • Just a guess: running manually (which works) you do _not_ have `--` in the arguments. – Craig Estey May 17 '22 at 19:56
  • I missed that in the text, but included it in the shell input/output block. I've edited the text. Thanks for catching that. – mmdski May 17 '22 at 19:59
  • I downloaded and ran your build commands. I'm on linux, so I don't have `leaks` (AFAICT, it's OSX only). Initially, I was suspicious as to what `$` would resolve to. But, I changed the test command to `valgrind` and it works as intended. So, I'd look at `build/CTestTestfile.cmake` to see what it's going to do. You could also try using `valgrind` to see if your issue is related to `leaks` vs. `ctest`. In `CMakeLists.txt`, I changed to: `find_program(valgrind REQUIRED True)` and `add_test(NAME memleak COMMAND valgrind $)` – Craig Estey May 17 '22 at 21:48
  • You're correct. `leaks` is only on OSX. I ran the test with `valgrind --error-exitcode=33` on Linux and it worked. Unfortunately, AFAIK, Valgrind is not available on Apple silicon. The `CTestTestfile.cmake` didn't reveal anything. I did run `ctest --verbose` and `leaks` is picking up the memory leak. (I'll update the post.) – mmdski May 17 '22 at 23:27

0 Answers0