C++ Sanitizers — AddressSanitizer, UBSan, ThreadSanitizer
C++ Sanitizer는 컴파일러가 코드에 계측(instrumentation)을 삽입해 런타임에 버그를 탐지하는 도구입니다. 정적 분석이 놓치는 런타임 의존 버그를 테스트 중에 즉시 발견할 수 있습니다.
1. AddressSanitizer (ASan)
섹션 제목: “1. AddressSanitizer (ASan)”메모리 관련 버그를 탐지합니다.
탐지 범위: 버퍼 오버플로, use-after-free, use-after-return, 힙/스택/전역 오버플로, double-free
# 컴파일 옵션g++ -fsanitize=address -fno-omit-frame-pointer -g -O1 main.cppclang++ -fsanitize=address -fno-omit-frame-pointer -g -O1 main.cpp// 탐지 예: use-after-freeint* p = new int(42);delete p;std::cout << *p; // ASan이 즉시 오류 보고ASan 출력 예시:
==ERROR: AddressSanitizer: heap-use-after-free on address 0x...READ of size 4 at 0x... thread T0 #0 0x... in main main.cpp:52. UndefinedBehaviorSanitizer (UBSan)
섹션 제목: “2. UndefinedBehaviorSanitizer (UBSan)”미정의 동작(UB)을 런타임에 검출합니다.
탐지 범위: 정수 오버플로, null 포인터 역참조, 정렬 위반, 배열 범위 초과, 유효하지 않은 bool 값
g++ -fsanitize=undefined -g -O1 main.cpp# 특정 검사만 활성화g++ -fsanitize=signed-integer-overflow,null -g main.cpp// 탐지 예: 부호 있는 정수 오버플로int max = INT_MAX;int overflow = max + 1; // UBSan: signed integer overflow
// 탐지 예: null 역참조int* p = nullptr;*p = 42; // UBSan: null pointer dereference3. ThreadSanitizer (TSan)
섹션 제목: “3. ThreadSanitizer (TSan)”멀티스레드 데이터 레이스를 탐지합니다.
TSan은 ASan과 동시에 사용할 수 없습니다.
g++ -fsanitize=thread -g -O1 main.cpp// 탐지 예: 데이터 레이스int counter = 0;
std::thread t1([&]{ counter++; });std::thread t2([&]{ counter++; });
t1.join(); t2.join();// TSan: data race on variable counterTSan 출력 예시:
WARNING: ThreadSanitizer: data race (pid=...) Write of size 4 at 0x... by thread T2: #0 main.cpp:6 Previous write of size 4 at 0x... by thread T1: #0 main.cpp:64. MemorySanitizer (MSan)
섹션 제목: “4. MemorySanitizer (MSan)”초기화되지 않은 메모리 읽기를 탐지합니다 (Clang 전용).
clang++ -fsanitize=memory -g -O1 main.cppint x;if (x > 0) // MSan: use of uninitialized value std::cout << "positive\n";5. Sanitizer 조합 권장
섹션 제목: “5. Sanitizer 조합 권장”# 개발/테스트 빌드 권장 조합g++ -fsanitize=address,undefined \ -fno-omit-frame-pointer \ -g -O1 \ main.cpp
# TSan은 별도 빌드 (ASan과 충돌)g++ -fsanitize=thread -g -O1 main.cppCMake 설정:
option(ENABLE_ASAN "Enable AddressSanitizer" OFF)option(ENABLE_TSAN "Enable ThreadSanitizer" OFF)
if(ENABLE_ASAN) target_compile_options(myapp PRIVATE -fsanitize=address,undefined -fno-omit-frame-pointer) target_link_options(myapp PRIVATE -fsanitize=address,undefined)endif()
if(ENABLE_TSAN) target_compile_options(myapp PRIVATE -fsanitize=thread) target_link_options(myapp PRIVATE -fsanitize=thread)endif()6. MSVC의 Sanitizer 지원
섹션 제목: “6. MSVC의 Sanitizer 지원”# Visual Studio 2019 16.9+/fsanitize=address ← ASan 지원# UBSan, TSan는 미지원 → Clang-cl 사용7. CI/CD 통합
섹션 제목: “7. CI/CD 통합”# GitHub Actions 예시- name: Build with ASan run: | cmake -B build -DENABLE_ASAN=ON cmake --build build
- name: Run tests with ASan run: | cd build && ctest --output-on-failure env: ASAN_OPTIONS: "detect_leaks=1:abort_on_error=1" UBSAN_OPTIONS: "print_stacktrace=1:halt_on_error=1"8. Sanitizer 환경 변수
섹션 제목: “8. Sanitizer 환경 변수”# 메모리 누수 탐지 활성화ASAN_OPTIONS=detect_leaks=1 ./myapp
# UBSan 상세 출력UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 ./myapp
# TSan 보고 무시 목록TSAN_OPTIONS=suppressions=tsan.supp ./myappSanitizer는 C++에서 가장 효율적인 버그 검출 도구입니다. CI 파이프라인에 ASan+UBSan 빌드를 추가하고 모든 테스트를 해당 빌드로 실행하면 메모리 오류와 미정의 동작을 배포 전에 잡을 수 있습니다. 성능 오버헤드(2~10×)가 있으므로 테스트 빌드에서만 활성화하세요.