1 C 语言程序常见的 coredump 原因及分析
C 语言编译生成的二进制程序在 Linux/Unix 系统下,最常见的崩溃信号是 SIGSEGV (段错误),会导致生成 core 文件(coredump)。
下面按发生频率从高到低,列出最常见的导致 coredump 的原因。
1.1 常见 coredump 原因排行
| 排名 | 原因 | 典型触发场景 | 示例代码 |
|---|---|---|---|
| 1 | 空指针解引用 | 使用 NULL 或未初始化的指针进行读写 |
char *p = NULL; *p = 'x'; |
| 2 | 野指针 / 悬空指针 | 使用已经 free() 或生命周期结束后的指针 |
free(ptr); *ptr = 1; |
| 3 | 数组/缓冲区越界 | 访问超过数组实际大小的下标 | int arr[10]; arr[10] = 5; |
| 4 | 栈溢出 (Stack Overflow) | 递归过深、声明超大局部数组 | char buf[10*1024*1024]; 或无限递归 |
| 5 | 堆内存使用错误 | 多次 free、释放后继续使用、堆缓冲区溢出 | free(ptr); free(ptr); |
| 6 | scanf 格式错误 | 忘记加取地址符 & |
int x; scanf("%d", x); |
| 7 | 不安全字符串操作 | strcpy、strcat、sprintf 等导致越界 |
char buf[8]; strcpy(buf, "too long string"); |
| 8 | 除零错误 | 整数或浮点数除以 0(触发 SIGFPE) | int a = 10 / 0; |
| 9 | 非法内存访问 | 修改只读内存区域(如字符串字面量) | char *s = "hello"; s[0] = 'H'; |
| 10 | 多线程数据竞争 | 未加锁访问共享变量,导致内存损坏 | 多个线程同时写同一全局变量 |
| 11 | 未初始化的指针 | 指针未赋值就直接使用 | int *p; *p = 100; |
| 12 | 返回局部变量地址 | 函数返回指向栈上临时变量的指针 | char* func() { char buf[100]; return buf; } |
1.2 其他可能导致 coredump 的情况
- 调用
abort()或assert()失败(触发 SIGABRT) - 地址未对齐访问(触发 SIGBUS)
malloc返回 NULL 后仍继续使用该指针- C++ 中未捕获的异常
1.3 如何预防和快速定位 coredump
1.3.1 编译时推荐选项
bash
gcc -g -O0 -Wall -Wextra -fsanitize=address -fno-omit-frame-pointer program.c -o program
常用选项说明:
- -g:生成调试信息
- -fsanitize=address:开启 AddressSanitizer(强烈推荐)
- -Wall -Wextra:开启更多编译警告
1.3.2 开启系统 core dump 生成
Bash
ulimit -c unlimited
1.3.3 使用 gdb 分析 core 文件
Bash
gdb ./program core
gdb 中常用命令:
- bt ------ 查看崩溃时的调用栈
- info locals ------ 查看当前函数的局部变量
- print <变量名> ------ 查看变量值
1.3.4 推荐调试工具
- AddressSanitizer (ASan)
- Valgrind
- UndefinedBehaviorSanitizer (UBSan)
1.4 总结:最常见的 Top 5 原因
- 空指针 / 未初始化指针解引用
- 数组/缓冲区越界(尤其是字符串操作)
- Use After Free(释放后继续使用)
- 栈溢出
- scanf 等输入函数忘记加 &