문제
행 포인터 표를 malloc 으로 잡는데, malloc 은 메모리를 0 으로 초기화하지 않는다. 게다가 이 표는 방금 free 된(=쓰레기로 채워진) 청크를 재사용하므로, 채우지 않은 칸은 NULL 이 아니라 0xABAB.. 같은 '그럴듯한 쓰레기 포인터'가 된다. 합산 루프가 채우지 않은 행까지 rows[i][j] 로 역참조하면 무효 주소 접근 → SIGSEGV. ("NULL 이면 걸러지겠지" 라는 방심이 깨지는 지점 — 쓰레기는 NULL 이 아니다)
https://github.com/yeooonee/Jungle-C-DebuggingLab/blob/main/challenges/08_uninitialized_read/bug.c
Jungle-C-DebuggingLab/challenges/08_uninitialized_read/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
문제풀이
해당 문제는 메모리 초기화 없이, 메모리 위치에 접근하는 문제이다. malloc 은 초기화 없이 메모리만 할당해주어, 해당 부분에 초기화 전까지는 쓰레기 값이 쌓여있다. 할당하는 메모리는 += 2 인데, 접근하는 메모리는 += 1 이라 잘못된 값에 접근하여 에러가 발생하고 있다. 미초기화 메모리는 NULL이 아니라 쓰레기 값이다.
이 문제를 해결하기 위해 초기화 해주는 calloc 을 사용하였다.
C 언어 malloc 과 free 사용하기 (sizeof)
malloc 과 free 는 한 쌍의 짝으로 같이 움직인다. malloc 은 언제 쓰는지?스택 변수는 크기를 컴파일할 때 정해야 한다. 실행 중에 크기가 정해지거나, 함수가 끝난 뒤에도 데이터가 살아있어야 하면
skylarcoding.tistory.com
여기서 두 가지 문제가 발생했는데,
- 처음에는 rows[i][j] == 0 으로 스킵을 시도했는데 검사하려고 역참조 하는 순간 이미 잘못된 값에 접근하고 있어 늦었다.
- calloc 만 하고 rows[i][j] 만 검사하였다. 검사 대상이 값이 아니라 포인터여야 했다.
- rows[i][j] 가 역참조인 것을 인지하지 못했다. rows[i][j] 는 *(rows[i] + j) 이다. rows[i] 에서 포인터 값을 꺼내고, j 만큼 더한 주소를 계산해서 * 실제 주소로 찾아가 값을 읽는다 는 의미이다. rows[i] 는 역참조가 아니다.
검사는 값이 초기화가 되어있어야 검사하는 의미가 있다.
마지막으로, 2씩 calloc 되어도 free 는 전체를 해주는게 덜 취약하다. free(NULL) 은 아무 행동도 하지 않도록 약속되어있기 때문이다.
