반응형
✅ 1. 댕글링 포인터란?
Dangling Pointer란?
이미 해제(free 또는 delete)된 메모리 영역을 참조하고 있는 포인터.
즉, 포인터는 메모리 주소를 저장하지만,
그 메모리 주소에 해당하는 실제 데이터가 더 이상 존재하지 않는 상태입니다.
📌 동적 할당 해제 예시
int* ptr = new int(42); // 동적 할당
delete ptr; // 메모리 해제
*ptr = 100; // 위험! dangling pointer 사용
위 코드에서 ptr은 delete 이후에도 여전히 메모리 주소를 가리키지만,
해당 메모리는 반환되어 재사용될 수 있기 때문에 더 이상 접근해서는 안 됩니다.
📌 지역 변수 주소 반환 예시
int* getPointer() {
int x = 10;
return &x; // 위험: x는 함수 종료 후 소멸됨
}
int main() {
int* p = getPointer();
std::cout << *p << std::endl; // undefined behavior
}
✅ 2. 발생 시점과 원인
| 원인 | 설명 | 예시 |
| 동적 메모리 해제 후 사용 | delete 혹은 free 이후에도 포인터 사용 | 위 동적 할당 예시 |
| 스코프 종료 후 지역 변수 주소 저장 | 함수가 끝나면서 지역 변수 소멸 후, 그 주소를 반환함 | 아래 예시 |
| Container의 요소 제거 후 참조 유지 | std::vector에서 요소 삭제했는데 참조나 포인터가 그대로 남음 | 게임 리스트에서 제거한 오브젝트 접근 |
✅ 3. 위험한 이유
- Undefined Behavior (정의되지 않은 동작):
어떤 동작이 일어날지 예측할 수 없음. 운 좋으면 작동, 운 나쁘면 프로그램 크래시, 버그 발생. - 보안 취약점:
이미 반환된 메모리를 다른 사용자나 해커가 사용하는 중일 수 있음. 이때 해당 메모리에 접근하면 Use-After-Free 취약점이 발생. - 게임 클라이언트에서의 예시 (Unity/C++):
- C++ 게임 클라이언트에서 오브젝트를 제거했는데, 해당 포인터를 계속 참조하면 크래시 발생.
- Unity에서는 자동 메모리 관리(Garbage Collector)가 있지만, Native Plugin이나 unsafe C# 코드에서 유사한 문제가 발생 가능.
✅ 4. 방지 방법
1) 포인터 초기화 후 삭제
int* ptr = new int(5);
delete ptr;
ptr = nullptr; // 댕글링 방지
nullptr로 초기화하면 접근 시 오류 감지 가능
2) unique_ptr, shared_ptr 사용 (C++11 이상)
std::unique_ptr<int> ptr = std::make_unique<int>(42);
// 자동으로 소멸되며 댕글링 방지
3) 스마트 포인터 또는 참조(reference) 사용 권장
4) 지역 변수의 주소를 반환하지 않기
✅ 5. 게임 클라이언트 개발에서의 위험 예시
🎮 Unreal Engine에서의 예시 (C++ 기반)
AEnemy* enemy = GetWorld()->SpawnActor<AEnemy>();
Destroy(enemy); // 액터 파괴
enemy->Attack(); // 댕글링 포인터 오류 발생 가능!
- Destroy()는 액터를 비동기적으로 제거하기 때문에, 이후 포인터가 여전히 유효하다고 착각할 수 있음.
- 해결책: IsValid() 체크 혹은 TWeakObjectPtr 사용.
반응형