C 프로그램의 버그를 의도적으로 재현하고 gdb로 분석하는 학습 케이스.
난이도 사다리 (Level 1 입문 -> Level 4 도메인 흉내) 순으로 정리.
| # | Lv | 케이스 | 증상 | 핵심 학습 |
|---|---|---|---|---|
| 01 | 1 | NULL dereference | Segmentation fault (exit 139) | NULL 포인터, SIGSEGV, backtrace |
| 03 | 1 | Off-by-one | 조용한 오답 / 범위 초과 | 경계 조건, watch, ASan |
| 04 | 1 | Uninitialized | 실행마다 다른 값 | 초기화 경로, -Wall, valgrind --track-origins |
| 02 | 2 | Buffer overflow | 인증 우회 / stack smashing | 스택 메모리, x/Nxb, strcpy -> strncpy |
| 05 | 2 | Double free | abort (exit 134) | 댕글링 포인터, free 후 NULL 화 |
| 06 | 2 | Use-after-free | 비결정적 깨짐/크래시 | 해제된 메모리 접근, ASan 3-스택 |
| 07 | 2 | Memory leak | 사용량 누적 -> OOM | 소유권, valgrind --leak-check |
| 08 | 3 | Heap corruption | 원인과 동떨어진 크래시 | 힙 버퍼 오버플로우, "터진 곳 != 원인" |
| 09 | 3 | Misaligned access | SIGBUS / 이식성 버그 | 정렬, memcpy, UBSan -fsanitize=alignment |
| 10 | 3 | NULL 함수 포인터 | SIGSEGV (PC=0) | 함수 포인터 검사, info registers pc |
| 11 | 4 | 인코딩 변환 | 상위 비트 바이트만 깨짐 | signed char 음수 인덱스 (EBCDIC/ASCII) |
| 12 | 4 | 고정 길이 레코드 | 필드 뒤에 쓰레기 따라붙음 | NUL 종료 누락, %.*s (COBOL 데이터) |
| 13 | 4 | 정렬 비교 함수 | 큰 값에서 순서 뒤집힘 | 비교 함수 정수 오버플로우, (x>y)-(x<y) |
Level 4 는 메인프레임 리호스팅 현장(인코딩 변환, 고정 폭 레코드, 대량 정렬)에서 실제로 마주치는 시나리오를 흉내낸 도메인 케이스.
각 케이스 디렉터리에서:
gcc -g bug.c -o bug
gdb ./bug
-g 플래그로 디버깅 심볼 포함 필수.
gdb 단독으로 부족한 메모리/정렬/오버플로우 버그는 sanitizer 와 valgrind 를 병행한다.
| 도구 | 강점 | 대표 케이스 |
|---|---|---|
| gdb | 크래시 시점 스택/변수/메모리 직접 확인 | 01, 10 |
ASan (-fsanitize=address) |
메모리 범위 초과/UAF/이중 해제, 원인 위치 정확 | 03, 05, 06, 08, 11, 12 |
| LeakSanitizer / valgrind | 누수 위치와 양, 초기화 출처 추적 | 04, 07 |
UBSan (-fsanitize=undefined) |
정렬 위반, 정수 오버플로우 등 정의되지 않은 동작 | 09, 13 |