[TIL] 220318 Dangling Pointer

신현철·2022년 3월 18일
0

TIL

목록 보기
2/5

이미 해제된 지역변수를 억지로 참조하면?

#include <stdio.h>
int *sub(int *, int);

int main(void)
{
    int i, q;
    int n[5] = {1, 2, 3, 4, 5};
    q = *sub(n, 5);
    printf("q = %d\n", q);

    return 0;
}
int *sub(int *p, int size)
{
    int i;
    int a[5] = {0};

    for (i = 0; i < size; i++){
        a[i] = p[i] + i;
    }

    return a;
}

위 코드는 모 시험에서 나온 문제인데, q 값을 printf로 출력했을 때 어떤 값이 나올지 적는 문제였다.
지인에게 질문을 받은 문제인데, 코드를 곰곰히 읽었을 때 사실 오류가 날 것이라고 생각했다.

우선 코드의 흐름부터 살펴보자.
1) main에서 n이라는 배열을 만들고, 포인터 함수인 sub에 넘겨준다
2) sub가 실행되고, sub 안에서 local variable인 a라는 배열이 생성된다.
3) a배열은 p배열 (=main의 n배열)의 값을 이용해서 값이 들어가고 a배열의 주소가 반환된다.
4) main으로 돌아와서 sub에서 반환된 배열 주소를 역참조하여 q에 넣어주고 출력한다.

언뜻 보면 q의 값으로 연산된 결과인 1이 나온다고 생각할 수 있다. 그러나 a는 local variable이고 sub함수에서 return이 실행되는 순간 메모리는 해제된다. 따라서 리턴해주는 주소는 참조해서는 안되는 주소이다.

c언어에서는 지역 변수는 메모리의 stack area에 위치한다. stack area는 함수가 종료되면 SP(stack pointer)가 바뀌면서 stack구조로 참조할 수 있는 위치가 바뀐다. 따라서 sub함수 종료 이후 main에서 q값을 역참조한다면, 이미 SP가 해제시킨 유효하지 않은 주소의 값을 갖게 된다.

실제로 코드를 실행하면 q=1이 나올 때도 있고, 그렇지 않고 에러가 날 때도 있다. 즉 예상할 수 없는 결과를 초래하는 잘못된 코드인 것이다.

이러한 문제는 c,c++ 같은 언어들에서 볼 수 있다. 객체지향 언어인 java 같은 경우에는 garbage collector가 더 이상 참조되지 않는 객체를 자동으로 파괴해주기 때문에 이러한 에러를 예방할 수 있지만, c,c++은 그렇지 않기에 이러한 코드가 예기치 못한 결과를 낳는다. 이런 pointer를 dangling pointer라고 부르며, dangling pointer는 Linux/Unix 에서는 segmentation fault, window에서는 general protection fault가 발생시킨다. 해당 내용은 위키피디아를 참고했다.
허상 포인터

이러한 방식을 해커들이 이용할 수도 있다고 한다. 메모리 관리가 정말 중요한다고 생각되는 대목이다.

profile
DB는 두부

0개의 댓글