문제
eb_snapshot() 이 저장하는 것은 "그 시점의 data 포인터(원시 주소)"다. 이후 eb_grow()가 realloc 으로 버퍼를 옮기면(주소 변경), 저장해 둔 스냅샷 포인터는 '이미 해제된 옛 블록'을 가리키게 된다(댕글링). 정리 시 eb_free() 는 현재 data 를 해제한 뒤 undo[] 의 옛 포인터들도 free 하는데, 그 블록들은 realloc 이 이미 해제한 것이라 → double free / invalid pointer 로 glibc abort(SIGABRT).
https://github.com/yeooonee/Jungle-C-DebuggingLab/blob/main/challenges/10_realloc_dangling/bug.c
Jungle-C-DebuggingLab/challenges/10_realloc_dangling/bug.c at main · yeooonee/Jungle-C-DebuggingLab
Krafton jungle week 5 debugging lab. Contribute to yeooonee/Jungle-C-DebuggingLab development by creating an account on GitHub.
github.com
문제풀이
그냥 run 해보면 ?? 위치에서 에러가 발생해서 어떤 함수가 원인인지 파악하기 어려웠다. main 에 break 를 찍고 디버깅 해보니 eb_free 함수 안에서 에러가 발생했다. eb_free 함수를 살펴보니, free를 하는 아래 부분에서 발생했는데 처음에는 free 의 소유권과 순서 문제인가 고민했다. 결국 어떤게 문제인지 모르겠어서, ai 의 도움을 받았다.
for (int i = 0; i < e->undo_n; i++) {
free(e->undo[i]);
}
free 에서 문제가 있으니 SIGABRT 에러가 발생했을 것이다. 그럼 이 부분은 어디서 선언하고 있는가? 를 확인해보면, eb_snapshot 에서 선언하고 있다. snapshot 에서 아래 copy 후에 snapshot 찍은 undo와 data 의 주소값이 같아졌다.
static void eb_snapshot(EditBuffer *e) {
if (e->undo_n < MAX_UNDO) e->undo[e->undo_n++] = e->data;
}

그런데 eb_push 에서 realloc 후에는 주소값이 달라졌다. realloc 후에는 자리가 모자라면 다른 곳으로 통째로 옮기고 새 주소를 준다. 그럼 e->undo[0]은 현재 쓰레기 값이 들어있는 realloc 이전의 주소를 바라보고 있다.

undo는 현재 e->data 의 snapshot 값을 찍어야 한다. 그럼 그냥 데이터만 가지고 있어도 되니, snapshot 에서는 현재 e->data 의 주소가 아닌 값만 가져오면 되는거다. 근데 e->data 에 몇개 들었을 줄 알고 가져오나? 모르기 때문에 malloc 을 사용해야 한다.

malloc 을 사용해서 각 배열 칸 안에 또 배열을 만들고 ... 그 칸에 snapshot 을 저장한다 .. 가 기본원리이다.
어려웠던 점
- gdb 로 문제가 터지는 곳까지는 갔는데, 어떻게 해결해야할지를 모르겠다. Ai 에게 확인하니 아래와 같은 흐름으로 파악하라고 하더라 .. 더 연습해봐야겠다.
- 어디서 터졌는지
- 해당 부분 관찰하기 (주소 관찰하기)
- 주소의 생성 ~ 삭제 일대기 추적
- 소유권 확인하기