Linux 中 core dump 异常的分析

news2024/9/23 11:25:17

目录

  • 一、概述
  • 二、发生 core dump 的原因
    • 1. 空指针或非法指针
    • 2. 数组越界或指针越界
    • 3. 数据竞争
  • 三、分析 core dump 的方法
    • 1. 启用 core dump
    • 2. 触发 core dump
      • 2.1 因空指针解引用而崩溃
      • 2.2 通过 信号触发 core dump
    • 3. 利用 gdb 分析 core dump


一、概述

在 UNIX 系统中,常将“主内存称为核心(core),因为在使用半导体作为内存材料之前,便是使用核心(core)。而核心映像(core image)就是 “进程”(process)执行当时的内存内容。当进程发生错误或收到 “信号”(signal)而终止执行时,系统会将核心映像写入一个文件,以作为调试之用,这就是所谓的核心转储(core dump)。

Core dump 是指在程序异常终止时,操作系统将程序的内存映像保存到磁盘上的一种机制。

在 Linux 系统中,core dump 提供了一种调试程序错误的重要方式,它记录了程序在崩溃时的内存状态,可以帮助开发人员快速定位问题。当程序因为某种原因(如段错误、非法指令等)异常终止时,Linux 系统会尝试将程序在内存中的映像、程序计数器、寄存器状态等信息写入到一个名为 core 的文件中,这个文件就是所谓的 core dump

以下是一些常见的导致 core dump 的错误:

  • 段错误(Segmentation fault
    • 程序访问了无效的内存地址,比如试图访问未分配的内存或者已经释放的内存
  • 空指针引用(Null pointer dereference
    • 程序试图使用空指针访问内存中的数据时,会导致空指针引用错误
  • 内存访问越界(Out of bounds memory access
    • 程序试图访问数组或者其他数据结构超出其边界范围的内存,就会发生内存访问越界错误
  • 使用已释放的内存(Use after free
    • 程序试图在已经释放的内存地址上进行读取或写入操作时,就会发生使用已释放的内存错误
  • 栈溢出(Stack overflow
    • 程序递归调用层数过深或者在栈上分配了过多的内存时,会导致栈溢出错误
  • 除以零(Division by zero
  • 无效的指令或操作码(Invalid instruction or opcode
    • 执行了不存在或无效的机器指令或操作码,会导致无效指令错误
  • 硬件故障或操作系统错误:如内存损坏、内核崩溃等情况

二、发生 core dump 的原因

在 Linux 中,发生 core dump 是因为程序发生了严重错误,导致程序被强制终止。当程序遇到一个无法处理的错误时,操作系统为了进行调试和分析,会将程序的内存空间中的所有数据,包括堆栈和堆的内容等,以一种特殊的文件格式保存到一个称为 core dump 的文件中。

当程序发生 core dump 时,可以使用调试工具(如 gdb)来分析 core dump 文件,找出导致程序崩溃的具体原因。调试工具可以提供堆栈跟踪、变量值查看等功能,帮助我们定位和解决问题。

1. 空指针或非法指针

空指针或非法指针(野指针、悬空指针)引起 core dump 是一种最常见的核心转储,大致可以有 3 种原因导致程序出现异常:

  1. 对空指针进行解引用等操作;
  2. 声明指针变量后未进行初始化,并直接进行操作,极大概率引发 core dump,此类未经初始化的指针,统称野指针;
  3. 对某个指针,调用了 free 函数或者 delet 函数,该指针指向的空间已经被释放,但未将该指针重新指向 NULL,此类指针成为悬空指针。对悬空指针再次操作,也会引发 core dump

2. 数组越界或指针越界

  • 数组越界:当程序访问数组中超出其有效索引范围的元素时,会发生数组越界错误。例如,如果一个数组有 5 个元素,但程序尝试访问第 6 个元素,就会导致越界错误。
  • 指针越界:当程序使用指针来访问无效的内存地址时,会发生指针越界错误。例如,如果一个指针指向了一个已经释放或未分配的内存区域,或者指针超出了其有效范围,就会导致指针越界错误。

3. 数据竞争

数据竞争是指多个线程同时访问共享的数据,并且至少一个线程试图对该数据进行写操作。当发生数据竞争时,由于缺乏同步机制,可能会导致未定义行为,其中包括 core dump

数据竞争可能导致以下问题之一:

  • 无效的内存访问:并发写入共享数据时,可能会导致内存损坏或非法内存访问,从而导致 core dump
  • 竞争条件:当多个线程操作共享数据而没有正确的同步时,可能会导致竞争条件的出现。例如,线程 A 读取共享数据,线程 B 写入共享数据,并且线程 A 使用了未正确同步的数据,从而导致 core dump
  • 死锁:当多个线程同时请求锁资源,并且循环等待对方释放锁资源时,就会发生死锁。这可能导致线程无法继续执行,最终导致 core dump

三、分析 core dump 的方法

1. 启用 core dump

默认情况下,程序运行崩溃导致 core dump,是不会生成 core 文件的,因为系统的 RLIMIT_CORE(核心文件大小)资源限制,默认情况下设置为 0。

先查看系統默认:ulimit -c 命令用于显示当前用户的 core dump 文件的大小限制。输出结果的含义如下:

  • 数字(以 KB 为单位),表示当前用户允许生成的 core dump 文件的最大大小限制
  • unlimited,表示当前用户允许生成任意大小的 core dump 文件
  • 0,表示当前用户不允许生成 core dump 文件

通过以下命令可在用户进程触发信号时启用 core dump 生成,并使用合理的名称将核心文件位置设置为 /tmp/请注意,这些设置不会永久存储,重启或者重新登录就会失效

$ ulimit -c unlimited
$ echo 1 | sudo tee /proc/sys/kernel/core_uses_pid
$ echo "/tmp/core-%e-%s-%u-%g-%p-%t" | sudo tee /proc/sys/kernel/core_pattern

使 core 文件名称是否带有 pid,配置文件 /proc/sys/kernel/core_uses_pid 的内容为 1,添加 pid;0为不添加 pid;

下面是 /tmp/core-%e-%s-%u-%g-%p-%t 的各个参数的含义:

%e:导致 core dump 的程序的可执行文件名。
%s:导致 core dump 的信号编号。
%u:导致 core dump 的程序的实际用户 ID。
%g:导致 core dump 的程序的实际组 ID。
%p:导致 core dump 的程序的进程 ID。
%t:core dump 发生时的时间戳(自 epoch 时间以来的秒数)。

因此,/tmp/core-%e-%s-%u-%g-%p-%t 会生成包含如下信息的 core 文件:

/tmp/core-<executable>-<signal>-<uid>-<gid>-<pid>-<timestamp>

要想永久开启 core dump 功能,需要修改配置文件 /etc/security/limits.conf,修改如下:

$ more  /etc/security/limits.conf
*               soft    core             unlimited
## 要关闭修改如下: *               soft    core             0

登出重新连接即可生效

通过如下命令可以查看详细显示信息:

$ ulimit -a
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 15135
max locked memory       (kbytes, -l) 65536
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 15135
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

2. 触发 core dump

下面使用两个简单的 C 程序作为示例。

2.1 因空指针解引用而崩溃

文件名为 test.c:

#include <stdio.h>

int main() {
    int *ptr = NULL;  // 声明一个空指针

    // 尝试解引用空指针
    printf("尝试解引用空指针...\n");
    printf("空指针的值为:%d\n", *ptr);  // 这里会引发未定义行为

    return 0;
}

编译并运行程序:

$ gcc -g -o test test.c
$ ./test

运行程序后,会在 /tmp/ 文件夹下生成一个 core 文件。

2.2 通过 信号触发 core dump

core dump 文件一般是在收到某个信号的时候结束产生,如果不指定特定的信号,应用程序按默认方式处理,默认处理的信号如下:

3) SIGQUIT      4) SIGILL     5) SIGTRAP   6) SIGABRT      7) SIGBUS       
8) SIGFPE      11) SIGSEGV   31) SIGSYS   24) SIGXCPU     25) SIGXFSZ    29) SIGIO

此例通过 SIGSEGV 信号触发 core dump,文件名为 test2.c:

#include <stdio.h>
#include <unistd.h>

int main(void)
{
    while (1)
        sleep(1);

    return 0;
}

编译并运行程序:

$ gcc -g -o test2 test2.c
$ ./test2

然后再打开一个终端,杀死这段进程:


这是,就会在 /tmp/ 文件夹下生成一个 core 文件。

3. 利用 gdb 分析 core dump

两个例子都是段错误导致的 core dump,所以用 gdb 调试的方法也是一样的,命令格式如下:

$ gdb <program_name> <core_dump_file>

比如先调试第一个例子的 core 文件,则输入如下命令:

$ gdb test /tmp/core-test-11-1000-1000-11695-1722948057

可以看到 gdb 提示在代码的第 8 行出错了:
如果函数关系调用关系很复杂,可以用 bt 命令(backtrace)查看调用堆栈(where 命令也有同样功能),如下图可知是在调用 main 函数时产生的段错误,可用 list 命令查看,具体就是 list 加函数名,如下图。然后通过 p(print) 命令,打印出 ptr 的值,可以发现 ptr 指针是一个空指针:


或者可以通过查看汇编代码来排查问题:

通过 disass 命令可以打印出出现错误的代码段:

再通过 info reg (info registers) 查看各个寄存器的值:

可以看到寄存器 rax 的地址为 0,说明这个指针 ptr 是个空指针。


第二个例子,也是同样用 gdb 打开 core 文件:

gdb test2 /tmp/core-test2-11-1000-1000-11802-1722948499

虽然这个段错误是因为我们人为地发送了 SIGSEGV 信号,导致了程序地段错误,而在打开 core 文件后,可以看出在执行 __GI___clock_nanosleep 函数时,遇到了段错误。

通常情况下,分析 core dump 问题,除了 core 文件之外,还会结合程序的 log 信息和系统的 log 信息(包括 kernel logsystemd log 等)一起分析。

如果我们不事先知道是由 SIGSEGV 信号导致段错误的,首先要用 bt 命令找到函数的调用关系链:


前面三个函数是封装过的库函数,所以没办法看见具体实现:

在前面输入 bt 命令查看堆栈情况时,有出现了两个变量,分别是 req 和 rem。这个两个变量是 nanosleep 函数的形参,原型是 int nanosleep(const struct timespec *req, struct timespec *rem)

print 命令打印出两个变量的地址:

再使用 info registers 命令查看寄存器状态,检查程序在崩溃时的上下文:


从寄存器状态来看,没有明显的错误迹象,函数的栈帧空间没什么问题,形参的位置和值也没什么问题,所有值看起来都在正常范围内。

当下是没办法直接了当的判断为人为干预造成 core dump,如果此时想到了信号会引发段错误,可以用 info signals 命令查看信号情况:


info signals 的输出中可以看出,SIGSEGV(Segmentation fault)信号是设置为在程序接收到该信号时停止执行并打印信息的。也就说,可以人为地使用 kill -11 发送了 SIGSEGV 信号来终止程序并生成 core dump

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1989888.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

sqli-labs第一关详细解答

首先判断是否有注入点 发现and 11 和 and 12结果一样&#xff0c;所以应该是字符型注入&#xff0c;需要对单引号做闭合 做闭合后发现报错&#xff0c;提示Limit 0,1&#xff0c;那就说明存在注入点&#xff0c;但是要注释掉后面的limit 0,1 使用--注释掉limit 0,1后&#xff…

25考研英语长难句Day05

25考研英语长难句Day05 【词组】【断句】 【词组】 单词解释gelimpsen.一瞥、瞥见rapidly adv.迅速&#xff1b;迅速地&#xff1b;高速&#xff1b;急速地&#xff1b;急促scene n.场景&#xff1b;&#xff08;尤指不愉快事件发生的)地点&#xff0c;现场&#xff1b;场面&a…

记录下泡面神器的满血复活-Kindle Voyage刷安卓系统记录

Kindle在国内已经没有服务了&#xff0c;一段时间内通过连手机热点(上下班通勤)&#xff0c;用内置浏览器访问微信读书&#xff0c;但体验不是很好&#xff0c;在考虑是否购买一个国内的墨水屏阅读器时&#xff0c;偶然想到了是否可以刷安卓&#xff0c;然后装微信读书的墨水屏…

超详细!网络安全知识入门及学习流程

第一章&#xff1a;网络安全的基本概念和术 一、网络安全的基本概念 1.保密性&#xff08;Confidentiality&#xff09; 定义&#xff1a;确保信息在存储、传输和处理过程中不被未授权的人员访问或获取。例子&#xff1a;企业的商业机密文件被加密存储&#xff0c;只有拥有正…

5个理由让你爱上CleanMyMac2025告别卡顿,迎接极速体验!

CleanMyMac是一款Mac电脑专用的清理工具&#xff0c;具有系统垃圾、大型旧文件、邮件附件、iTunes垃圾、软件卸载残余等清理功能。 它采用先进的扫描技术&#xff0c;快速识别并清除垃圾文件&#xff0c;释放磁盘空间&#xff0c;提高系统运行速度。 同时&#xff0c;它还具备…

Android经典实战之Kotlin中实现圆角图片和圆形图片

本文首发于公众号“AntDream”&#xff0c;欢迎微信搜索“AntDream”或扫描文章底部二维码关注&#xff0c;和我一起每天进步一点点 实现圆角是一个很常见的需求&#xff0c;也有很多种方式&#xff0c;这里介绍2种&#xff0c;实现起来都不麻烦&#xff0c;很方便 方法一&…

JS+CSS案例:可适应上下布局和左右布局的菜单(含二级菜单)

今天,我给大家分享一个原创的CSS菜单,整个菜单全由CSS写成,仅在切换布局时使用JS。合不合意,先看看效果图。 本例图片 接下来,我来详细给大家分享它的制作方法。 文件夹结构 因为涉及到了样式表切换,所以,你需要借鉴一下我的文件夹结构。 CSS文件夹: reset.css 用于…

【Dash】Dash Layout

一、Dash Layout Dash apps are composed of two parts. The first part is the layout, which describes what the app looks like. The second part describes the interactivity of the app. To get started, create a file named app.py, copy the code below into it, a…

Linux权限-chmod命令

作者介绍&#xff1a;简历上没有一个精通的运维工程师。希望大家多多关注作者&#xff0c;下面的思维导图也是预计更新的内容和当前进度(不定时更新)。 根据前面Linux用户介绍&#xff0c;里面涉及到超级管理员&#xff0c;普通用户&#xff0c;系统用户&#xff0c;既然用户有…

微信小程序-Vant组件库的使用

一. 在app.json里面删除style&#xff1a;v2 为了避免使用Vant组件库和微信小程序组件样式的相互影响 二.在app.json里面usingComponents注册Vant组件库的自定义组件 "usingComponents": {"van-icon": "./miniprogram_npm/vant-weapp/icon/index&qu…

Discourse 将主题打印成 PDF

Discourse 允许用户通过使用 打印主题&#xff08;Print topic&#xff09; 快捷键来生成 PDF 文件。这个快捷键针对操作系统的不同&#xff0c;可以通过键盘上的 ? 来进行查看。 大部分操作系统: ctrlpMacOS: ⌘p 使用快捷键后会打开一个新的浏览器窗口&#xff0c;在这个新…

【LeetCode每日一题】——653.两数之和 IV - 输入二叉搜索树

文章目录 一【题目类别】二【题目难度】三【题目编号】四【题目描述】五【题目示例】六【题目提示】七【解题思路】八【时间频度】九【代码实现】十【提交结果】 一【题目类别】 广度优先搜索 二【题目难度】 简单 三【题目编号】 653.两数之和 IV - 输入二叉搜索树 四【…

使用MAC电脑、iPhone 真机调试 H5页面

使用MAC电脑、iPhone 真机调试 H5页面 简介Safari 浏览器设置iPhone 手机设置开始调试 简介 为方便在 H5开发过程中在真实手机调试 H5页面&#xff0c;可进行一下设置 Safari 浏览器设置 在 Mac 电脑打开浏览器后&#xff0c;点左上角的" Safari 浏览器" -> “设…

Android OCR 谷歌OCR TextRecognition用法介绍

谷歌OCR TextRecognition用法介绍 文章目录 谷歌OCR TextRecognition用法介绍简介作用如何使用1 在project-build.gradle/setting.gradle添加maven仓库2.在module-build.gradle添加仓库依赖3.初始化4.使用InputImage5.进行识别 完整代码使用效果&#xff1a; 所有代码在Github-…

IEEE报告解读:存储技术发展趋势分析

1.引言 随着数据科学、物联网&#xff08;IoT&#xff09;和永久存储需求的快速增长&#xff0c;对大规模数据存储的需求正在迅速增加。存储技术的发展趋势直接关系到数据的可靠性和经济性。本文将根据IEEE最新发布的《2023年国际器件与系统路线图》&#xff0c;深入探讨各种存…

私网环境下如何使用云效流水线进行 CI/CD?

作者&#xff1a;怀虎 场景介绍 代码库、制品库等数据资产托管在内部办公网&#xff0c;公网不能访问&#xff0c;希望能够使用云效流水线进行 CICD 的编排和控制。 整体方案 云效流水线可以托管用户的私网环境内的机器&#xff0c;并将构建任务调度到这些机器上&#xff0…

PPT创作新纪元C-Ai PPT助手

前端必备工具推荐网站(免费图床、API和ChatAI等实用工具): http://luckycola.com.cn/ 解锁PPT创作新纪元 —— 遇见C-AiPPT助手 在这个快节奏的时代&#xff0c;无论是商务演示还是学术汇报&#xff0c;一份精美且内容丰富的PPT都是不可或缺的利器。但你是否曾为寻找合适的PPT…

81.SAP ME - SAP SMGW Getway Monitor

目录 1.起因 2.SMGW Displaying Logged On Clients Displaying Remote Gateways Display and Control Existing Connections Deleting a Connection Displaying Gateway Release Information Displaying Parameters and Attributes of the Gateway Change Gateway Pa…

QModbus例程分析

由于有一个Modebus上位机的需要&#xff0c;分析一下QModbus Slave的源代码&#xff0c;方便后面的开发。 什么是Modbus Modbus是一种常用的串行通信协议&#xff0c;被广泛应用于工业自动化领域。它最初由Modicon&#xff08;目前属于施耐德电气公司&#xff09;于1979年开发…

AXS4054:单节锂电池充电管理芯片特性与应用推荐

AXS4054是一款单节锂离子电池恒流/恒压线性充电器&#xff0c;芯片集成功率晶体管&#xff0c;充电电流可以用外部电阻设定&#xff0c;蕞大持续充电电流可达600mA,非常适合便携式设备应用&#xff0c;适合USB电源和适配器电源工作&#xff0c;内部采用防倒充电路&#xff0c;不…