Memory bugs like buffer overflows or use-after-free errors can be tricky to debug and may lead to undefined behavior or security vulnerabilities. Fortunately, AddressSanitizer is a useful tool built into modern compilers like GCC and Clang that helps detect these types of errors at runtime. This tutorial explains how to use AddressSanitizer with CMake.
Let's say we have a minimal CMakeLists.txt
file that includes an optional AddressSanitizer toggle:
cmake_minimum_required(VERSION 3.27)
project(myapp)
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)
set(CMAKE_CXX_STANDARD 17)
add_executable(${PROJECT_NAME} main.cpp)
if (ENABLE_ASAN)
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
endif ()
This setup defines an ENABLE_ASAN
option that, when turned on, adds -fsanitize=address
to both the compiler and linker options.
Here's a simple C++ program in the main.cpp
file:
#include <cstdio>
#include <cstdlib>
#include <cstring>
int main() {
char *buff = (char *) malloc(20);
strcpy(buff, "Hello world");
free(buff);
printf("%s\n", buff);
return 0;
}
This code allocates memory, copies a string into it, frees the memory, and then attempts to access it afterward - demonstrating a classic use-after-free error.
Execute the following command to generate the required build files in debug mode with AddressSanitizer enabled:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug -DENABLE_ASAN=ON
Build the project:
cmake --build build
Now run the program:
./build/myapp
Example output (truncated):
==2169==ERROR: AddressSanitizer: heap-use-after-free on address 0x503000000040 at pc 0x7b6acfe6c5a5 bp 0x7ffc23d03e80 sp 0x7ffc23d03628
READ of size 2 at 0x503000000040 thread T0
#0 0x7b6acfe6c5a4 in puts ../../../../src/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc:1236
#1 0x5adfed8e4275 in main /home/testuser/myproject/main.cpp:9
#2 0x7b6acf62a1c9 (/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9) (BuildId: 232274c0019767b821da1c6ebc2df43e60503035)
#3 0x7b6acf62a28a in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x2a28a) (BuildId: 232274c0019767b821da1c6ebc2df43e60503035)
#4 0x5adfed8e4164 in _start (/home/testuser/myproject/build/myapp+0x1164) (BuildId: 80fa506f76588e691a157bc094a280dc4eae6735)
0x503000000040 is located 0 bytes inside of 20-byte region [0x503000000040,0x503000000054)
...
This output clearly identifies a heap-use-after-free bug, pinpoints the line in the code (main.cpp:9
), and even shows the memory address involved.
Leave a Comment
Cancel reply