Dangling Pointer는 컴퓨터 프로그래밍에서 유효한 객체를 가리키고 있지 않은 포인터를 말한다. 즉 유효하지 않은 주소를 참조하고 있는 포인터를 말하며 주로 객체 파괴시 발생하고, 할당 해제된 메모리를 다른 프로세스에게 재할당 해주게 되면 기존 프로그램이 허상포인터를 역참조하게 되어 예측할 수 없는 결과를 초래할 수 있고, 유닉스나 리눅스에서 segmentation fault나 윈도우에선 general protection fault가 발생할 수 있다. 객체 지향 프로그래밍의 경우 Garbage Collector로 인해 더 이상 참조되지 않은 객체를 파괴함으로써 예방할 수 있지만, C와 C++의 경우 예외되기 때문에 각별히 주의해서 사용해야한다. 자바 같은 언어에는 메모리 할당 해제를 명시적으로 하는 메커니즘이 없기 때문에 허상포인터가 발생하지 않고, Garbage Collector에서 객체가 어떤 참조에서도 닿을 수 없는 경우 메모리를 할당 해제한다.
(1) Dangling Pointer의 원인
① 메모리의 객체를 명시적으로 지우거나 스택 메모리 파괴시 포인터의 변경을 수행하지 않을 경우
{
char *dp = NULL;
/* ... */
{
char c;
dp = &c;
}
/* c falls out of scope */
/* dp is now a dangling pointer */
}
위 그림에서 처럼 c의 메모리가 중괄호를 빠져나감과 동시에 메모리가 해제되고 dp는 해제된 메모리를 바라보게 된다.
※ 해결책 : 내부 블록이 종료되기 전 dp에게 NULL값을 주는 것이다.
② 메모리 해제 후 Dangling Pointer를 NULL로 설정 안할 경우
#include <stdlib.h>
void func()
{
char *dp = malloc(A_CONST);
/* ... */
free(dp); /* dp now becomes a dangling pointer */
/* ... */
}
위 dp의 경우 dp가 가리키는 메모리는 할당해제 되었지만, dp의 메모리 자체 영역은 해제가 되지 않아, 아직까지 dp의 영역을 사용할 수 있다.
※ 해결책 : free로 할당된 메모리 영역을 해제 후 반드시 Dangling Pointer가 된 pointer 변수에 반드시 NULL값을 준다.
#include <stdlib.h>
void func()
{
char *dp = malloc(A_CONST);
/* ... */
free(dp); /* dp now becomes a dangling pointer */
dp = NULL; /* dp is no longer dangling */
/* ... */
}
③ 스택 할당된 지역 변수의 주소를 리턴
int *func(void)
{
int num = 1234;
/* ... */
return #
}
위 코드처럼 호출된 함수가 리턴되면 변수들을 위한 공간은 할당해제되고 이것들은 쓰레기 값을 갖게 된다.
※ 해결책 : num에대한 포인터가 반환되어야 한다면 num은 반드시 함수 이상의 유효 범위를 가져야 한다.
(2) Dangling Pointer 해결책
① Dangling Pointer를 회피하는 기법으로 사용하기
포인터의 재설정을 보장하는 대체버전의 free()함수구현하거나 Macro Function을 구현하여 방지할 수 있다.
#include <assert.h>
#include <stdlib.h>
#define FREE(ptr) if(ptr) { free(ptr); ptr = NULL; } /* Macro Function Define */
/* Alternative version for 'free()' */
void safefree(void **pp)
{
/* in debug mode, abort if pp is NULL */
assert(pp);
if (pp != NULL) { /* safety check */
free(*pp); /* deallocate chunk, note that free(NULL) is valid */
*pp = NULL; /* reset original pointer */
}
}
int f(int i)
{
char *p = NULL, *p2;
p = (char *)malloc(1000); /* get a chunk */
p2 = p; /* copy the pointer */
/* use the chunk here */
safefree((void **)&p); /* safety freeing; does not affect p2 variable */
safefree((void **)&p); /* this second call won't fail */
char c = *p2; /* p2 is still a dangling pointer, so this is undefined behavior. */
return i + c;
}
※ Segmentation Fault
프로그램이 허용되지 않은 메모리 영역에 접근을 시도하거나, 허용되지 않는 방법으로 메모리 영역에 접근을 시도할 경우 발생한다. 예를 들어 읽기 전용 영역에서 어떤 내용을 쓰려고 시도하거나, 운영체제에서 사용하는 영역에 다른 내용을 덮어쓰려고 하는 경우 발생한다.
const char *s = "hello world";
*s = 'H';
위 코드에서 문자열 hello world는 읽기 전용 메모리이고, 프로그램이 로드 되었을 때 운영체제는 이 문자열과 상수 데이터를 읽기 전용 세그먼트에 배치한다. 프로그램이 실행되면, 변수 s는 이 문자열의 위치를 가리키게 되고, 'H'라는 문자열을 s를 통해 메모리에 기록하려는 시도는 Segmentation Fault를 일으키게 된다. 또 아래와 같이 아무것도 가리키지 않은 포인터(NULL 포인터)에 값을 할당하려고 하는 경우 발생된다.
int* ptr = (int*) 0x00000000;
*ptr = 1;
Smart Pointer (0) | 2020.04.22 |
---|---|
Virtual Function (0) | 2020.04.21 |
Vector 컨테이너 (0) | 2020.04.09 |
STL Vector와 List의 차이점 (0) | 2020.03.25 |
정적(static)&공유(shared) 라이브러리 (0) | 2020.03.25 |
댓글,
야미야미얌얌
프로그래밍 및 IT 기술