본문으로 이동
메뉴 여닫기
환경 설정 메뉴 여닫기
개인 메뉴 여닫기
로그인하지 않음
지금 편집한다면 당신의 IP 주소가 공개될 수 있습니다.

허상 참조(Dangling Reference, 현수 참조)는 포인터나 참조가 이미 해제되었거나 수명이 끝난 기억 장소를 여전히 가리키고 있는 상태이다. 포인터일 때는 댕글링 포인터(허상 포인터)라고 한다.

참조 변수 자체는 살아 있는데 그 대상인 기억 장소는 시스템에 반납되었으므로, 그 참조로 읽으면 쓰레기 값이 나오고 쓰면 이미 다른 용도로 다시 할당된 데이터를 망가뜨린다. C·C++ 처럼 기억 장소 해제를 프로그래머가 직접 하는 언어에서 생긴다. 결과가 정해지지 않은 동작(undefined behavior)이라 바로 드러나지 않고 나중에 엉뚱한 곳에서 오류가 난다.

/* 1. 해제한 뒤에도 포인터를 쓴다 */
int *p = malloc(sizeof(int));
free(p);
*p = 10;            /* p 는 허상 참조 */

/* 2. 지역 변수의 주소를 돌려준다 */
int *f(void) {
    int x = 5;
    return &x;      /* 함수가 끝나면 x 의 기억 장소는 사라진다 */
}

/* 3. 별명 중 하나로 해제한다 */
int *a = malloc(sizeof(int));
int *b = a;         /* a 와 b 는 별명 */
free(a);            /* b 가 허상 참조가 된다 */
  • 프로그램이 비정상 종료되거나 데이터가 조용히 망가진다
  • 해제된 기억 장소를 공격자가 원하는 데이터로 다시 채우게 한 뒤 허상 포인터로 호출하게 만들면 임의 코드가 실행된다. 이것이 Use After Free 취약점이다
  • 해제한 직후 포인터에 NULL 을 넣는다
  • 지역 변수의 주소를 함수 밖으로 돌려주지 않는다
  • C++ 의 스마트 포인터(unique_ptr, shared_ptr)로 수명을 자동 관리한다
  • 가비지 컬렉션을 쓰는 언어(자바, 파이썬)는 참조가 남아 있는 객체를 해제하지 않으므로 허상 참조가 생기지 않는다
  • Rust 는 컴파일할 때 빌림 검사기로 참조가 대상보다 오래 살지 못하게 막는다
  • 언어 설계 기법으로 묘비(tombstone, 대상과 참조 사이에 중간 칸을 두고 해제 때 표시) 기법과 자물쇠와 열쇠(lock-and-key, 참조와 대상에 같은 값을 두고 접근 때 비교) 기법이 있다

가비지와의 차이

편집 원본 편집
구분 허상 참조 가비지
상태 참조는 있는데 기억 장소가 없다 기억 장소는 있는데 참조가 없다
원인 너무 일찍 해제 해제를 잊음, 참조를 덮어씀
결과 잘못된 읽기·쓰기, 보안 취약점 기억 장소 낭비, 메모리 누수