AddressSanitizer doesn't always catch memory leaks
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
A simple C program seems to be generating false negatives when compiled with `-fsanitize=address`.
```c
// Built using:
// `clang -fsanitize=address -fuse-ld=lld -o out example.c`
// `clang -fsanitize=address -fuse-ld=lld -g -o out example.c`
// `clang -fsanitize=address -fuse-ld=lld -rtlib=compiler-rt -unwindlib=libunwind -o out example.c`
// `clang -fsanitize=address -fuse-ld=lld -rtlib=compiler-rt -unwindlib=libunwind -g -o out example.c`
// Run using:
// `./out`
// `ASAN_OPTIONS=detect_leaks=1 ./out # just in case it helped`
#include
#include
int f(void) {
FILE* file = fopen("example.c", "r");
if (!file) {
fprintf(stderr, "Couldn't open %s\n", "example.c");
return 1;
}
char* buffer = malloc(1024);
return 0;
}
int main(int argc, char** argv) {
f();
}
```
I've verified this on both Arch Linux with Clang built from b6d7afe53465517ed944a43165b6885fab460c4e (config below), and on [Compiler Explorer](https://godbolt.org/z/x7naxqdch). This doesn't look like a regression, since versions 5 through 22 don't seem to detect a leak, either. `llvm-readelf` seems to indicate that lots of AddressSanitizer functions exist in the code.
Changes that have no effect:
* [Building with C++ and using `new char[1024]` instead of `malloc(1024)`](https://godbolt.org/z/ja8oE91x1)
* [Changing how much memory is allocated from (e.g. `1 << 30`)](https://godbolt.org/z/WM7jTG76j)
Making any one of the following changes (in isolation) causes the leak to be detected on trunk, as shown in the Compiler Explorer example:
* [Building with `-fsanitize=leak` instead of `-fsanitize=address`](https://godbolt.org/z/WxYvf89ob)
* [Building with GCC](https://godbolt.org/z/YY9EsY6x6)
* [Manually inlining `f()` into `main`](https://godbolt.org/z/TzTW4PGoc)
* [Replace `int main(int argc, char** argv)` with `int main(void)`](https://godbolt.org/z/5TMEj9rr4)
* [Replace `FILE* file = fopen("example.c", "r");` with `int x = 0; int* file = &x;`](https://godbolt.org/z/YMhhEvf4j)
* [Change `f`'s return type to `void`](https://godbolt.org/z/cPs7feezT)
* [Building with C++ and replacing `malloc(1024)` with `std::allocator().allocate(1024)`](https://godbolt.org/z/Yva9KMsW5)
## LLVM config
I configured LLVM with the following arguments:
```
cmake -Sllvm -Bbuild -GNinja \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_PROJECTS="clang;clang-tools-extra;lld;lldb" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind;compiler-rt" \
-DLLVM_INSTALL_UTILS=Yes \
-DLLVM_TARGETS_TO_BUILD=X86 \
-DLLVM_USE_LINKER=mold \
-DLIBCXX_ABI_UNSTABLE=Yes \
-DLIBCXX_ENABLE_STATIC_ABI_LIBRARY=Yes \
-DLIBCXX_HARDENING_MODE=fast \
-DLLVM_ENABLE_LIBCXX=Yes \
-DLLVM_BINUTILS_INCDIR="$HOME/opt/binutils/include" \
-DLLVM_ENABLE_LTO=Thin
```
Contributor guide
Research direction
Start by reproducing the leak in the embedded example.c with the listed clang -fsanitize=address commands and compare the linked variants. Inspect the AddressSanitizer leak-detection path implicated by the differences in f(), main(), and fopen(); done means the unfreed allocation is reported under the original AddressSanitizer invocation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 42/100