::Introduction::
Double-free bugs, where a program frees the same allocation more than once, are a common cause of heap corruption and security vulnerabilities in C and C++ programs.
AddressSanitizer already detects double-free bugs. However, ASan detects a much broader set of memory-safety errors by instrumenting memory accesses and maintaining shadow memory and redzones. This can impose significant execution-time and memory overhead. In particular, resource-constrained embedded environments may not have sufficient memory or runtime budget to run ASan at all. For projects that only need double-free detection, this cost can be unnecessary.
This RFC proposes DoubleFreeSanitizer (DSan), a standalone compiler-rt sanitizer focused on detecting double-free errors. DSan intercepts allocation and free APIs, tracks per-allocation state and stack traces, and reports an error when an allocation is freed again.
DSan does not require an LLVM IR instrumentation pass. It consists of a compiler-rt runtime and the minimal Clang driver support needed for the new -fsanitize=doublefree option.
::Naming::
The original intended name was DFSan, standing for “Double-Free Sanitizer.” However, DFSan is already widely used for DataFlowSanitizer, whose Clang option is -fsanitize=dataflow.
To avoid that naming conflict, this implementation currently uses DSan and the runtime name dsan.
I am open to renaming the sanitizer if the community prefers another name.
::Proposal::
The patch adds a new sanitizer option:
-fsanitize=doublefree
The option links the standalone DSan runtime. The runtime tracks allocation state in allocator metadata. Each allocation records:
- whether the allocation is currently allocated;
- whether it has already been freed;
- the allocation stack trace;
- the first free stack trace; and
- the requested allocation size.
When the program frees a pointer that DSan has already observed as freed, DSan reports the error and terminates the program.
For example:
ERROR: DoubleFreeSanitizer: double-free on address 0x…
Second free (the invalid free) of address 0x…:
#0 free
#1 mainFirst free of address 0x…:
#0 free
#1 mainOriginal allocation of address 0x…:
#0 malloc
#1 mainSUMMARY: DoubleFreeSanitizer: double-free on address 0x…
::Implementation::
The implementation follows the structure and conventions of existing standalone compiler-rt sanitizers.
::Clang::
The patch adds DoubleFreeSanitizer to Sanitizers.def and introduces the -fsanitize=doublefree command-line option.
The Clang driver links the dsan runtime when this option is enabled. DSan is handled as a standalone runtime, similarly to LeakSanitizer, rather than requiring compiler-inserted instrumentation.
::compiler-rt::
The patch adds compiler-rt/lib/dsan, which provides:
- a standalone allocator with per-chunk metadata;
- interceptors for malloc, calloc, realloc, free, aligned allocation APIs, and related allocation functions;
- interceptors for C++ allocation and free operators;
- stack-trace collection for allocations and frees;
- runtime flags and default-option support;
- optional user hooks such as __dsan_default_options and __dsan_is_turned_off;
- thread, TLS, and fork support based on sanitizer_common infrastructure; and
- CMake and GN build integration.
::Tests::
The patch adds a compiler-rt/test/dsan test suite, including coverage for allocator behavior, runtime options, suppressions, C++ allocation/free operators, threading, TLS, fork behavior, Linux-specific behavior, and Darwin-specific behavior.
::Motivation::
DSan is intended for users who want focused double-free detection without enabling the complete AddressSanitizer feature set.
Potential use cases include:
- CI configurations where ASan’s execution-time or memory overhead is too high;
- Embedded devices that need to detect double-free errors but cannot run ASan because of resource constraints; This is the situation faced by my company.
::Limitations::
DSan intentionally focuses on double-free detection. It is not a replacement for AddressSanitizer.
In particular, DSan does not aim to detect:
- heap-buffer-overflow;
- stack-buffer-overflow;
- use-after-free reads or writes;
- use-after-return;
- use-after-scope; or
- other invalid memory accesses that ASan detects.
Platform support follows the platforms supported by the DSan runtime and corresponding Clang driver integration. The initial implementation includes support for the sanitizer platforms and architectures covered by the added compiler-rt and driver configuration.
::Future work::
Possible future directions include:
- expanding platform and allocator coverage;
- revisiting whether DSan should remain a distinct sanitizer or eventually share more implementation with an existing sanitizer runtime.
::Feedback requested::
I would appreciate feedback on:
- whether a standalone double-free-only sanitizer is useful to the LLVM community;
- the proposed DSan name, especially suggestions for a better name that does not conflict with DataFlowSanitizer;
- expected sanitizer-option compatibility;
Assisted-by: GPT-5.6 Terra