AddressSanitizer, 메모리 오류를 실행 중에 찾는 법

AddressSanitizer는 컴파일 때 넣는 런타임 검사로, 버퍼 오버플로와 use-after-free 같은 메모리 오류를 실행 중에 잡습니다.

이 글은 Clang AddressSanitizer 문서와 GCC Instrumentation Options, sanitizers wiki를 2026-08-30 기준으로 정리한 일반 설명이며, 플랫폼과 컴파일러 버전에 따라 세부 동작은 달라질 수 있습니다.

AddressSanitizer는 무엇인가?

한 줄 답: 이 도구는 컴파일러 계측과 런타임 라이브러리로 메모리 오류를 실행 중에 찾는 검사입니다.

Clang 문서는 이를 C/C++용 빠른 메모리 오류 검출기로 설명하며, 공식 별칭으로 ASan이라고도 부릅니다. 핵심 구성은 컴파일러 계측 모듈런타임 라이브러리로 나뉩니다. 런타임 라이브러리는 malloc을 대체해 할당 관련 동작을 검사 흐름에 포함합니다.

컴파일러는 메모리 접근 명령을 계측하고, 실행 중 런타임이 접근 유효 범위를 확인합니다. 즉, 소스 코드만 읽어 판단하는 정적 분석기가 아니라, 검사 옵션을 넣어 빌드한 프로그램을 실제로 실행하면서 발생한 오류를 보고하는 방식입니다.

공식 문서가 안내하는 계측 프로그램의 전형적인 성능 저하는 약 2배입니다. 따라서 테스트 환경에서 실행할 때 실행 시간 증가와 메모리 부담을 반드시 함께 고려해야 합니다.

어떻게 켜나?

한 줄 답: 컴파일과 링크에 -fsanitize=address를 넣고, 스택 추적을 위해 -fno-omit-frame-pointer를 함께 씁니다.

이 옵션은 각 소스 파일을 컴파일할 때와 최종 실행 파일을 링크할 때 모두 포함해야 합니다. 최종 링크 과정에서는 원시 ld 대신 clang, clang++ 또는 GCC 드라이버를 사용해야 이 도구의 런타임 라이브러리가 실행 파일에 정상적으로 연결됩니다.

-g 옵션은 디버깅 정보를 포함하고, -fno-omit-frame-pointer는 더 읽기 좋은 스택 추적에 도움을 줍니다. Clang 문서는 합리적인 실행 성능을 위해 -O1 이상 최적화를 권장하며, 완전한 스택 추적이 필요할 경우 -fno-optimize-sibling-calls로 형제·꼬리 호출 최적화를 막을 수 있다고 안내합니다.

clang++ -O1 -g -fsanitize=address -fno-omit-frame-pointer example_UseAfterFree.cc

ASAN_OPTIONS=help=1 환경 변수를 설정하면 프로그램 시작 시 사용할 수 있는 옵션 목록을 확인할 수 있습니다. 심볼을 사람이 읽기 편한 형태로 표시하려면 llvm-symbolizerPATH에 두거나 ASAN_SYMBOLIZER_PATH로 경로를 직접 지정할 수 있습니다.

어떤 오류를 잡나?

한 줄 답: 힙·스택·전역의 범위 초과 접근과 use-after-free, double-free 같은 메모리 오류를 실행 중에 보고합니다.

이 검사는 메모리 접근의 유효 범위와 할당 상태를 중심으로 이뤄집니다. 힙·스택·전역 버퍼의 범위 초과 접근, 해제 후 사용, 반환 후 사용, 스코프 후 사용이 대표적인 검사 대상입니다.

  • use-after-free: 해제된 메모리를 다시 사용하는 오류
  • heap-buffer-overflow, stack-buffer-overflow, global-buffer-overflow: 힙, 스택, 전역 버퍼 범위를 벗어난 잘못된 접근
  • use-after-return, use-after-scope: 반환되었거나 범위를 벗어난 로컬 저장 공간을 사용하는 오류
  • 초기화 순서 문제 (Initialization order bugs)
  • double-free, invalid free
  • 메모리 누수 (Memory leaks)

메모리 누수 검출은 현재 실험적 기능입니다. Linux에서는 기본으로 켜지고, macOS에서는 ASAN_OPTIONS=detect_leaks=1로 수동으로 켤 수 있으며, 그 밖의 플랫폼에서는 아직 지원되지 않습니다.

오류를 발견하면 표준 오류(stderr)에 원인 메시지를 출력하고 0이 아닌 종료 코드로 즉시 끝납니다. 기본 동작은 첫 번째 오류 발생 시 종료하는 것이며, 이는 설계상 의도된 방식입니다. 일반적인 검출에서는 오탐(False Positive)을 만들지 않는다고 Clang 문서가 설명하지만, 컨테이너 오버플로 추가 검사의 주의점은 다음 절에서 다룹니다.

못 잡거나 주의할 점은 무엇인가?

한 줄 답: 정적 링크는 지원하지 않고, 프로덕션 실행 파일에 런타임을 넣는 용도가 아니며, 일부 접근은 최적화나 미계측 코드 때문에 놓칠 수 있습니다.

이 검사는 네이티브 실행보다 실제 메모리를 상당히 더 사용하며, 정확한 부담은 메모리 할당 크기에 따라 달라집니다. 할당 단위가 작을수록 오버헤드가 커질 수 있고, 스택 메모리는 최대 3배까지 증가한 사례가 문서에 제시되어 있습니다.

64비트 플랫폼에서는 16TB 이상 가상 주소 공간을 매핑하지만 실제로 예약하는 것은 아닙니다. 따라서 ulimit 같은 리소스 제한 도구가 평소와 다르게 동작할 수 있습니다.

실행 파일의 정적 링크는 지원하지 않습니다. 또한 런타임은 보안 민감한 제약을 고려해 개발된 것이 아니므로 프로덕션 실행 파일에 링크하는 용도가 아니라 오직 테스트 환경에 사용해야 합니다.

컴파일러가 명백히 잘못된 메모리 접근을 검사 전 최적화 단계에서 제거해 버리면 이 검사가 오류를 볼 수 없습니다. 모든 오류를 찾으려면 전체 구성 요소를 다시 빌드해야 하며, Clang 계측 코드와 GCC 계측 코드 또는 두 컴파일러의 런타임 구현을 서로 섞을 수 없습니다.

컨테이너 오버플로 추가 검사는 오탐 가능성이 있으므로, 앞서 말한 일반 검출의 특성과 명확히 구분해야 합니다. GCC 문서는 이 옵션을 -fsanitize=thread 또는 -fsanitize=hwaddress와 함께 사용할 수 없다고 안내합니다.

FAQ

한 줄 답: 테스트 환경에서 빌드 방식과 런타임 제약을 함께 확인하면 됩니다.

질문답변
프로덕션 바이너리에 이 런타임을 넣어도 됩니까?버그 검출 도구이며 프로덕션 실행 파일에 링크하는 용도가 아니므로 테스트 환경에서 사용해야 합니다.
정적 링크와 함께 쓸 수 있습니까?실행 파일의 정적 링크는 지원하지 않습니다.
일부 번역 단위만 다시 컴파일해도 됩니까?일부만 다시 빌드해도 동작하지만, 모든 오류를 찾으려면 모든 구성 요소를 다시 빌드해야 합니다.
UBSan과 같은 검사입니까?미정의 동작(UB) 검사는 다른 sanitizer 도구이며, 이 글의 대상인 메모리 오류 검사와는 다릅니다.

출처

한 줄 답: 본문 사실과 짧은 빌드 명령은 2026-08-30 기준으로 확인한 공식 문서 세 곳만 사용합니다.