Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Leak Checking on OS X #17

Closed
jamesjuett opened this issue Aug 27, 2022 · 5 comments · Fixed by #110
Closed

Leak Checking on OS X #17

jamesjuett opened this issue Aug 27, 2022 · 5 comments · Fixed by #110

Comments

@jamesjuett
Copy link
Contributor

jamesjuett commented Aug 27, 2022

It's not clear how students with Macs should locally check for memory leaks. This has also been a problem in the past with Valgrind, which hasn't worked on OS X for a good while. The fallback then was to have students transfer their code over to CAEN and run Valgrind there. It'd be great to get away from that if we could.

It looks like the leak checking via LSan isn't enabled by default as part of ASan for clang on OS X (ASan does get you LSan by default on Linux/WSL.) To get leak checking, you need to additionally specify ASAN_OPTIONS=detect_leaks=1.
https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer

To further complicate things, it seems like Apple Clang/llvm that ships with Xcode (and that we have all students with macs install via xcode-select --install) doesn't support that detect_leaks=1 option.
google/sanitizers#1026

Xcode users can detect leaks using the Instruments tool. I'm not familiar with it, but some searching online makes me feel like it's a bit complicated/heavyweight compared to how we've generally used Valgrind or the sanitizers. There's also a leaks command-line tool, that I believe offers similar functionality.

If you get the "non-Apple" version of clang/llvm via e.g. brew install llvm, then the sanitizers work fine on OS X (with the additional option to enable leak checking). Maybe it's worth modifying our setup at some point to use this instead of installing the compiler via the xcode-select --install? (EDIT: This doesn't work on arm64 for those with newer macs.)
.
I don't think that would have a significant effect on anything other than Xcode, in which case we would need to decide whether it's worth adding instructions to configure Xcode's build system to use the non-apple version, or if it would work out to just let XCode exist with its own separate compiler than what students end up using if they compile with the makefile via the terminal.

@awdeorio awdeorio transferred this issue from another repository Oct 26, 2022
@jamesjuett
Copy link
Contributor Author

It looks like the description above is incomplete. The "non-Apple" version of clang/llvm on arm64 does not support leak checking either.

@awdeorio
Copy link
Contributor

awdeorio commented Feb 8, 2023

It looks like the description above is incomplete. The "non-Apple" version of clang/llvm on arm64 does not support leak checking either.

Update: I was able to do leak checking on arm64:

$ brew install llvm
$ make published
...
/opt/homebrew/opt/llvm/bin/clang++ --std=c++11 -Wall -pedantic -g -Wno-sign-compare -Wno-comment -fsanitize=address -fsanitize=undefined List_compile_check.cpp -o List_compile_check.exe
...
ASAN_OPTIONS=detect_leaks=1 ./List_compile_check.exe
...
==13045==ERROR: LeakSanitizer: detected memory leaks

Update 2: While the ASAN leak detector runs, it give false positives. It reports leaks for this program, with no libraries.

int main() {
  return 0;
}

@awdeorio
Copy link
Contributor

awdeorio commented Feb 21, 2023

This is summary of how to use the address sanitizer to detect leaks on different platforms.

WSL and Linux

Enable the address sanitizer at compile time.

$ export CXXFLAGS="--std=c++11 -Wall -Werror -pedantic -g -fsanitize=address"
$ make test

macOS x86_64

Enable the address sanitizer at compile time and run time. This works with Apple Clang.

$ export CXXFLAGS="--std=c++11 -Wall -Werror -pedantic -g -fsanitize=address"
$ export ASAN_OPTIONS="detect_leaks=1"
$ make test

macOS arm64

EDIT: ASAN leak detection does not work on arm64. The macOS leaks tool does. Note: you must compile without ASAN flags for leaks to work.

$ make main.exe
$ leaks -quiet -atExit -- ./main.exe

CAEN Linux

Enable the address sanitizer at compile time.

$ export CXXFLAGS="--std=c++11 -Wall -Werror -pedantic -g -fsanitize=address"
$ make test

The EECS 280 address sanitizer tutorial recommends the additional flag -fsanitize=undefined. The default RHEL GCC on CAEN Linux is not a full install. You can load a full-featured GCC with:

$ module load gcc/9
$ export CXXFLAGS="--std=c++11 -Wall -Werror -pedantic -g -fsanitize=address -fsanitize=undefined"
$ make test

@awdeorio
Copy link
Contributor

Good news! The leaks tool that ships with macOS Xcode tools works for leak detection! Here's how to do it.

$ unset CXX  # leaks is incompatible with ASAN
$ make ./List_compile_check.exe
$ leaks -quiet -atExit -- ./List_compile_check.exe
...
STACK OF 1 INSTANCE OF 'ROOT LEAK: <malloc in List<int>::push_front(int const&)>':
5   dyld                                  0x1aea9be50 start + 2544
4   List_compile_check.exe                0x102d6eebc main + 1312  List_compile_check.cpp:64
3   List_compile_check.exe                0x102d6f640 List<int>::insert(List<int>::Iterator, int const&) + 84  List.h:351
2   List_compile_check.exe                0x102d6f190 List<int>::push_front(int const&) + 36  List.h:200
1   libc++abi.dylib                       0x1aed808b0 operator new(unsigned long) + 32
0   libsystem_malloc.dylib                0x1aec2ec20 _malloc_zone_malloc_instrumented_or_legacy + 128 
====
    3 (96 bytes) ROOT LEAK: <malloc in List<int>::push_front(int const&) 0x14cf04170> [32]
       2 (64 bytes) <malloc in List<int>::push_front(int const&) 0x14cf04130> [32]
          1 (32 bytes) <malloc in List<int>::push_back(int const&) 0x14cf04150> [32]
...

@shallow-beach
Copy link

Good news! The leaks tool that ships with macOS Xcode tools works for leak detection! Here's how to do it.

$ unset CXX  # leaks is incompatible with ASAN
$ make ./List_compile_check.exe
$ leaks -quiet -atExit -- ./List_compile_check.exe
...
STACK OF 1 INSTANCE OF 'ROOT LEAK: <malloc in List<int>::push_front(int const&)>':
5   dyld                                  0x1aea9be50 start + 2544
4   List_compile_check.exe                0x102d6eebc main + 1312  List_compile_check.cpp:64
3   List_compile_check.exe                0x102d6f640 List<int>::insert(List<int>::Iterator, int const&) + 84  List.h:351
2   List_compile_check.exe                0x102d6f190 List<int>::push_front(int const&) + 36  List.h:200
1   libc++abi.dylib                       0x1aed808b0 operator new(unsigned long) + 32
0   libsystem_malloc.dylib                0x1aec2ec20 _malloc_zone_malloc_instrumented_or_legacy + 128 
====
    3 (96 bytes) ROOT LEAK: <malloc in List<int>::push_front(int const&) 0x14cf04170> [32]
       2 (64 bytes) <malloc in List<int>::push_front(int const&) 0x14cf04130> [32]
          1 (32 bytes) <malloc in List<int>::push_back(int const&) 0x14cf04150> [32]
...

it is possible to have leaks detect a still reachable leak?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants