[1. 개요]
힙 메모리 관련 하여, SIGSEGV 시그널 발생 사례 중...
free(): invalid pointer 오류 발생하는 경우가 있음.
구체적인 상황은
- new[] 를 이용하여, 동적 길이의 배열을 생성
- 해당 배열을 사용
- delete[] 를 이용하여 리소스 해제 => 이 때 오류가 발생하는데...
문제는 gdb 를 통해서 delete[] 한 메모리 주소가 오염되었는지 확인해보았는데,
- 최초 할당 시, 받은 주소였고,
- 심지어, 해당 메모리에 접근하여 배열 내 값도 정상적으로 확인 할 수 있었음.
즉, 아래와 같은 상황은 아니라는 것이다.
- double free 를 시도한다 던가...
- new[] 로 할당한 메모리를 단순히 delete 로 해제한다 던가...
[2. 원인]
위 상황에 대한 원인은 다른 힙 메모리에 발생한 overflow 에 있었다.
#include <iostream>
int main()
{
int * arr0 = new int[5];
int * arr1 = new int[6];
int * arr2 = new int[7];
arr0[0] = 123;
arr1[0] = 456;
arr2[0] = 789;
std::cout << "alloc!!!" << std::endl;
std::cout << "arr0: " << arr0 << std::endl;
std::cout << "arr1: " << arr1 << std::endl;
std::cout << "arr2: " << arr2 << std::endl;
arr0[6] = 99;
std::cout << "dealloc!!!" << std::endl;
delete []arr1;
std::cout << "terminate..." << std::endl;
return 0;
}
먼저, glibc 에서 힙 구현은 각 할당 블록 앞뒤에 size, flags, next 등의 정보를 유지한다.
- 이 정보는 개발자가 직접 확인 할 수 는 없어 보이는데..
즉, 해당 메모리 블록의 해제하는 free() 나 delete 시 이러한 메타데이터를 확인해야 하는데,
이 메타데이터가 오염되어있기 때문에 오류가 발생하는 것이다.
[3. 해결]
이러한 heap 메모리에 대한 buffer overflow 를 찾기 위해서, gdb 를 활용해도 되고,
컴파일 시, -fsanitize=address 옵션을 사용해서 조금 더 쉽게 찾을 수 있다.
- -g 옵션도 추가해서, 심볼 정보도 포함해야 한다.
실제 실행하면, heap-buffer-overflow 가 발생한 구간을 소스코드와 라인 수를 포함하여 알려준다.
[4. cmake 적용]
현재는 리눅스에서만 적용 가능하고, (윈도우도 가능은 하나 visual studio 2019 이상 부터 가능하긴 함. #clang? )
set(SANITIZE_FLAGS "-fsanitize=address -fno-omit-frame-pointer")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${SANITIZE_FLAGS}")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${SANITIZE_FLAGS}")
[5. 참고 사항]
void* 에 대한 delete 연산은 위험한 동작이다.
아래 오류(or 문구)가 발생하는 경우 void* 에 대한 delete 연산이 있는지 확인해보도록 한다.
- AddressSanitizer: alloc-dealloc-mismatch (operator new [] vs operator delete)
'C++' 카테고리의 다른 글
구조체 대입 연산 (0) | 2025.04.15 |
---|---|
Segmentation fault 사례4 (0) | 2025.04.14 |
Segmentation fault 사례2 (0) | 2025.04.01 |
STL priority_queue (0) | 2021.10.28 |
가변인자 템플릿 (0) | 2021.10.27 |