暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【线上排错】记一次Linux的“段错误(吐核)”排查步骤

左羊公社 2021-12-20
10880

你无法游向新的地平线,直到你有勇气告别海岸。(by 威廉·福克纳)


前言

事情起因这个样子的,去年12月中旬的一个下午左羊正在听着小曲编着码,突然就收到我们掌柜的生产环境预警信息。我们的视觉抓拍程序的核心是一个.so算法文件,我们通过Python程序去调用它,左羊怀疑是因为参数发生的问题,暂时还不能确定劳烦大家继续向下看吧。

小羊啊,咱们那个视觉抓拍程序执行过程中报了个“段错误(吐核)”的异常你来处理,十分紧急,尽快处理下。


排查

1.首先理解下啥是段错误(吐核)/Segmentation fault (core dumped)?

段故障(通常简称为segfault)是计算机软件运行过程中可能出现的一种特殊错误情况。简而言之,当程序试图访问不允许访问的内存位置,或试图以不允许的方式访问内存位置时,就会发生段错误。

A segmentation fault (often shortened to segfault) is a particular error condition that can occur during the operation of computer software. In short, a segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed[1]


2. 产生段错误(吐核)的原因是什么呢?

在引用.so文件时以下几类做法容易导致段错误,基本都是我们给C程序传入了错误参数造成的。

  • 解引用空指针

    C语言中,如果一个指针变量的值为NULL,解引用这个指针时,会导致程序崩溃(Segmentation fault)。

  • 访问不可访问的内存空间(如内核空间)

    例如系统保护的内存地址写数据最常见就是给一个指针以0地址

  • 访问不存在的内存地址

    例如内存越界(数组越界,变量类型不一致等)

  • 等等其他(左羊调查有其他情况在做补充)


3. 如何排查产生段错误(吐核)的原因呢?

左羊在这里准备了一个复现错误的程序供大家测试。这里左羊采用的是解引用空指针的形式复现。

#include <stdio.h>
int main(void)
{
printf("Hello_c/r/n");
int *helloWorld = NULL;
*helloWorld = 1;
}
复制

 

3.1. 可以获取到.so 文件源码的情况下,我们可以使用gcc -g 的方式编译.c文件,然后使用gdb ./appname的方式进入debug模式排查。

gcc -g -rdynamic HelloC.c
复制

a.out是咱们的执行文件,执行它即可复现问题。中文输出为【段错误(吐核)】英文输出为【Segmentation fault (core dumped)】它们的意思是一样的。

./a.out
复制

下面咱们使用gdb ./appname的方式来排除出现问题的原因

 gdb ./a.out
复制

(gdb)输入run以debug的方式运行程序
(gdb)run
复制

到这里咱们就能够发现是哪里出现了问题,问题的原因是代码中出现了解引用空指针的情况,处理掉即可。


3.2. 在无法获取到.so 文件源码的情况下,我们因该怎么办呢。左羊此次就属于无法获取到.so 文件源码的情况。

首先我们发现在没有使用gdb的方式运行时,系统给我们抛出了“段错误(吐核)/Segmentation fault (core dumped)”信息提示。

什么是吐核/Core Dump?

Core的意思是内存, Dump的意思是扔出来, 堆出来.

开发和使用Unix程序时, 有时程序莫名其妙的down了, 却没有任何的提示(有时候会提示core dumped).  这时候可以查看一下有没有形如core.进程号的文件生成, 这个文件便是操作系统把程序down掉时的内存内容扔出来生成的,  它可以做为调试程序的参考.core dump又叫核心转储, 当程序运行过程中发生异常, 程序异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 叫core dump。[2]

如何使用core文件?

gdb appname 核心转储文件名
gdb appname core.****
复制
复制
没有core文件生成咋整?
由于Linux的资源有限制,一个可执行文件的吐核文件有可能会特别的大,多次吐核会造成内存,储存等资源的极大浪费,所以一定要随用随关哦。这里就牵扯到Linux的资源限制的知识点,左羊这里只有浅显理解大家可以自行深入了解下,例如百度搜索ulimit。
ulimit -a
复制

这里的【core file size】指的就是核心转储文件,参数为0代表无法写入,我们来修改其大小即可

ulimit -c 1024 单位是字节
ulimit -c unlimited 为无上限
复制

这里我们已经设置为无上限了,接下来我们再次执行下程序看看有没有核心转储文件生成。

core即为核心转储文件,我们通过gdb命令查看下报错信息。

这样我们即可定位问题了


小结

其实左羊这里的段错误(吐核)就是:

Python在调用.so文件时向其发送了一个非法的虚拟地址,通知操作系统内核给进程发送11号信号,进程收到了一个11号信号,导致进程异常终止。找出调用位置,重新检查参数就处理啦~

 

参考资料:
[1]段错误(吐核)的解释:https://stackoverflow.com/questions/30126079/a-segmentation-fault
[2]Core Dump解释:https://www.cnblogs.com/wuxi/archive/2013/05/04/3060319.html
复制


[

END

]


关注左羊公社



文章转载自左羊公社,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论