허상 포인터(Dangling pointer)는 컴퓨터 프로그래밍에서 더 이상 유효하지 않은 메모리 영역을 가리키고 있는 포인터를 의미한다. 영문 명칭인 '댕글링 포인터'로도 널리 불리며, '와일드 포인터(Wild pointer)'와 함께 유효하지 않은 객체를 참조하는 포인터의 대표적인 사례에 해당한다.
허상 포인터는 일반적으로 객체가 파괴되거나 메모리가 해제된 이후에도 해당 포인터 변수가 여전히 그 메모리 주소를 가리키고 있을 때 발생한다. 예를 들어 C 언어에서 free() 함수나 C++에서 delete 연산자를 사용하여 동적 할당된 메모리를 해제하면 해당 메모리 영역은 시스템에 반환되지만, 이를 가리키던 포인터 변수는 자동으로 초기화되지 않아 해제된 주소를 계속 참조하게 된다. 이 상태의 포인터가 허상 포인터이다.
허상 포인터가 발생하는 주요 원인은 다음과 같다.
- 동적 할당된 메모리를 해제한 후 포인터를 NULL로 재설정하지 않은 경우
- 함수 내부에서 선언된 지역 변수의 주소를 반환한 경우. 함수가 종료되면서 해당 변수는 스택에서 제거되므로 반환된 포인터는 유효하지 않은 주소를 가리키게 된다.
- 블록(scope) 내에서 선언된 지역 변수의 주소를 블록 외부의 포인터가 참조하는 경우. 블록이 종료되면서 변수가 소멸하면 포인터는 허상 상태가 된다.
허상 포인터를 역참조(dereference)하여 접근할 경우, 해당 메모리 영역은 이미 다른 용도로 재할당되었을 가능성이 있으므로 예측할 수 없는 동작(Undefined Behavior)이 발생한다. 구체적으로는 세그멘테이션 오류(Segmentation fault), 데이터 손상, 보안 취약점(Use-After-Free 취약점) 등이 나타날 수 있다.
허상 포인터를 방지하기 위한 방법으로는 메모리 해제 직후 포인터를 NULL로 설정하는 방법이 가장 기본적이다. C++에서는 스마트 포인터(smart pointer)를 사용하여 메모리 수명을 자동으로 관리함으로써 허상 포인터 발생을 원천적으로 회피할 수 있다. Java, C#, Python 등 가비지 컬렉션(Garbage Collection)을 채택한 언어에서는 명시적인 메모리 해제가 없으므로 허상 포인터 문제가 발생하지 않는다.