llvm / llvm/llvm-project

AddressSanitizer doesn't always catch memory leaks

Open
#189,431 6 comments 1 reaction 0 assignees View on GitHub
compiler-rt:asan compiler-rt:lsan
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.