目录
错误现象
我们在Linux
环境下编程中,有时执行编译好的文件时会出现段错误(吐核),这是经常出现的一个错误。
错误原因
- 解引用空指针
- 访问不可访问的内存空间(如内核空间)
- 访问不存在的内存地址
- 试图写一个只读内存空间(如代码段)
- 栈溢出(函数递归调用)
- 使用未初始化的指针(定义时没有初始化或者已经回收)
错误演示
对一个空指针进行解引用
吐核解释
吐出了一个“核心转储文件”(coredump
文件)即崩溃文件
程序确认出现错误时的“临终遗言” 写入核心转储文件,也是使用gdb
调试器最常用到的场景
崩溃文件查找
我们尝试ls -a
查看全部文件 (包含默认隐藏的文件)发现也并没有相关的新文件产生
其实操作系统有限制,默认不允许随意吐核,在一个工程中coredump
文件有可能会特别大,多次吐核过于占存,这样随意吐核会影响机器性能,一定要慎用。
我们通过指令查看与程序相关的属性,其中会包含核心转储文件信息
第一条core file
就是coredump
—— 核心转储文件,size
为0
表示不允许吐核,更改一下文件大小就可以顺利产出吐核文件了。
通过指令更改为大小为无限制 ulimit -c unlimited
我们再执行./main
,再次吐核。
之后 ls
就会出现core.3616
文件,数字后缀不同机器会不一样,这个不用在意。这个就是核心转储文件,我们成功通过操作查看到了。
仔细查看文件详情,发现文件确实占存很大:
那么我们通过vim
进入文件内部,看看它究竟是什么样子的:
果然如我们所料看不太懂,不知所云,这时候就借助我们老搭档gdb
调试器的力量
崩溃文件调试
gdb 可执行文件名 + 核心转储文件名
核心转储文件通过不同的可执行文件可能吐出不同的核,所以要带上可执行文件名,告诉操作系统这个核心转储文件是哪个可执行文件吐出的。
在这个程序中我们就输入gdb main core.3616
,回车后就可以定位程序错误原因了:
红色方框中显示了在main.c
文件中的Add函数
中第6
行对应的*p = 100;
这句代码有问题,导致程序异常终止,因为空指针不能解引用。
蓝色方框是一个比较重要的概念,11号信号,它是段错误(Segmentation fault
)的典型图腾。
那么这错误的第6行代码到底是怎么执行的?
可以通过bt
指令查看函数调用栈:
所以是因为main
函数调用Add
函数再调用Add2
函数,就在第6行出现了错误。这就是它的调用情况。