linux程序莫名异常怎么查

2024-04-12 02:58

本文主要是介绍linux程序莫名异常怎么查,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

内存异常经常导致程序出现莫名其妙的错误,往往很难查证,本文介绍在linux下的各种常见内存异常的查证工具和方法。

1 访问空指针/未初始化指针/重复释放内存

对于像访问空指针、未初始化指针(非法地址),重复释放内存等内存异常,linux默认会抛异常。

比如下面代码有空指针访问,编译运行后会coredump

int main()
{int *p=0;*p=6;return 0;
}

对于此类问题,我们只要在gcc编译程序时加入-g选项,同时在运行时能够生成coredump文件,利用gdb就可以定位到具体的问题代码行。

1.1 开启coredump

**ulimit -c  unlimited** //unlimited表示不限制coredump文件大小,也可指定一个具体值来限制文件最大长度。

1.2 定制core文件名

默认的coredump文件名为core,如果想自己定制core文件名,可以运行如下命令:

**echo "./core-%e-%p-%t" > /proc/sys/kernel/core_pattern** 

可以在core_pattern模板中使用变量还很多,见下面的列表:

%% 单个%字符

%p 所dump进程的进程ID

%u 所dump进程的实际用户ID

%g 所dump进程的实际组ID

%s 导致本次core dump的信号

%t core dump的时间 (由1970年1月1日计起的秒数)

%h 主机名

%e 程序文件名

1.3 使用gdb定位代码行

通过gdb即可定位出错代码行

root@ubuntu:/home/zte/test# gcc null.cc -g
root@ubuntu:/home/zte/test# ./a.out 
Segmentation fault (core dumped)
root@ubuntu:/home/zte/test# gdb a.out core
.......
Core was generated by `./null'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0  0x00000000004004fd in main () at null.cc:4
4    *p=6;

2、函数栈溢出

局部变量的写越界可能会破坏函数栈导致程序出现各种异常行为,但是OS默认不会在越界的第一现场coredump,因此导致问题查证非常困难。

幸运的是我们可以通过gcc的编译选项-fstack-protector 和 -fstack-protector-all在函数栈被破坏的函数返回时抛异常,从而可以很方便地定位问题所在函数。

代码示例

int main()
{int a=5;int *p=&a;p[3]=6;return 0;
}


上面代码会破坏函数栈,如果我们用gcc直接编译运行,不会抛异常。但是加了编译参数-fstack-protector 和 -fstack-protector-all后,再运行就会抛异常。下面是具体命令执行结果。

root@ubuntu:/home/zte/test# gcc t.c
root@ubuntu:/home/zte/test# ./a.out 
root@ubuntu:/home/zte/test# gcc t.c -fstack-protector -fstack-protector-all -g
root@ubuntu:/home/zte/test# ./a.out 
*** stack smashing detected ***: ./a.out terminated
Aborted (core dumped)
```
可以进一步用gdb的bt命令定位出问题的函数。
```
root@ubuntu:/home/zte/test# gdb a.out core
。。。。。。。。
Core was generated by `./a.out'.
Program terminated with signal SIGABRT, Aborted.
#0  0x00007f6bcfab5c37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0  0x00007f6bcfab5c37 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007f6bcfab9028 in __GI_abort () at abort.c:89
#2  0x00007f6bcfaf22a4 in __libc_message (do_abort=do_abort@entry=1, fmt=fmt@entry=0x7f6bcfc01d70 "*** %s ***: %s terminated\n")at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007f6bcfb8d83c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f6bcfc01d58 "stack smashing detected")at fortify_fail.c:38
#4  0x00007f6bcfb8d7e0 in __stack_chk_fail () at stack_chk_fail.c:28
#5  0x00000000004005aa in main () at t.c:7
(gdb) q


3 越界读写动态分配内存/读写已释放动态分配内存

动态分配内存读写越界、读写已释放动态分配内存系统往往不会抛异常,我们可以使用electric-fence来使得读写越界内存/已释放内存后立刻抛异常,加速问题定位。

3.1 安装Electric fence

sudo apt-get install electric-fence

3.2 使用Electric fence

下面是越界写代码

#include <stdlib.h>
int main()
{int *p = (int*)malloc(sizeof(int));p[1] = 6;return 0;
}


如果使用gcc直接编译运行,不会抛异常。

我们可以加上参数 -lefence -g编译后运行,就会抛异常。通过gdb的bt打印即可定位到问题代码行。

root@ubuntu:/home/zte/test# gcc malloc_read_free.cc -lefence -g
root@ubuntu:/home/zte/test# ./a.out Electric Fence 2.2 Copyright (C) 1987-1999 Bruce Perens <bruce@perens.com>
Segmentation fault (core dumped)autogen.sh


4 内存泄漏

C/C++程序经常被内存泄漏问题困扰,本文介绍使用gperftools来快速定位内存泄漏问题。

4.1 安装gperftools工具

4.1.1 安装automake

sudo apt-get install automake

4.1.2 编译安装libunwind

从https://github.com/libunwind/libunwind/releases下载最新版本的libunwind源码包

解压到/usr/local/src目录

cd 解压源码目录

./autogen.sh

./configure

make -j6

make install

4.1.3 编译安装gperftools

从https://github.com/gperftools/gperftools/releases下载最新版本的gperftools源码包

解压到/usr/local/src目录

cd 解压源码目录

./autogen.sh

./configure

make -j6

make install

4.2 内存泄漏检测

下面是一段简单的内存泄漏源码

int main()
{int *p = (int*)malloc(sizeof(int));return 0;
}

编译代码、运行工具检察内存泄漏,注意设置下

root@ubuntu:/home/zte/# gcc leak.cc -g
root@ubuntu:/home/zte/# env HEAPCHECK=normal LD_PRELOAD=/usr/local/lib/libtcmalloc.so ./a.out 
WARNING: Perftools heap leak checker is active -- Performance may suffer
Have memory regions w/o callers: might report false leaks
Leak check _main_ detected leaks of 4 bytes in 1 objects
The 1 largest leaks:
*** WARNING: Cannot convert addresses to symbols in output below.
*** Reason: Cannot run 'pprof' (is PPROF_PATH set correctly?)
*** If you cannot fix this, try running pprof directly.
Leak of 4 bytes in 1 objects allocated from:
@ 40053f 
@ 7f334da06f45 
@ 400469 
If the preceding stack traces are not enough to find the leaks, try running THIS shell command:
pprof ./a.out "/tmp/a.out.8497._main_-end.heap" --inuse_objects --lines --heapcheck  --edgefraction=1e-10 --nodefraction=1e-10 --gv
If you are still puzzled about why the leaks are there, try rerunning this program with HEAP_CHECK_TEST_POINTER_ALIGNMENT=1 and/or with HEAP_CHECK_MAX_POINTER_OFFSET=-1
If the leak report occurs in a small fraction of runs, try running with TCMALLOC_MAX_FREE_QUEUE_SIZE of few hundred MB or with TCMALLOC_RECLAIM_MEMORY=false, it might help find leaks more repeatabl
Exiting with error code (instead of crashing) because of whole-program memory leaks

上面的关键的输入信息是:

Leak of 4 bytes in 1 objects allocated from:

@ 40053f   //内存分配的指令地址

@ 7f334da06f45 

@ 400469 

由于工具没有直接输出问题代码行,我们通过反汇编来定位代码行:

objdump -S a.out  //反汇编程序

截取汇编代码如下:

int main()
{40052d:55                   push   %rbp40052e:48 89 e5             mov    %rsp,%rbp400531:48 83 ec 10          sub    $0x10,%rspint *p = (int*)malloc(sizeof(int));400535:bf 04 00 00 00       mov    $0x4,%edi40053a:e8 f1 fe ff ff       callq  400430 <malloc@plt>40053f:48 89 45 f8          mov    %rax,-0x8(%rbp)return 0;400543:b8 00 00 00 00       mov    $0x0,%eax

我们注意到40053f就是对应代码行int *p = (int*)malloc(sizeof(int));

至此,内存泄漏的元凶被揪出来了,呵呵。


https://cloud.tencent.com/info/e1ee255a3cd7993a301ffe75bbcfe031.html

这篇关于linux程序莫名异常怎么查的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/895913

相关文章

关于MongoDB图片URL存储异常问题以及解决

《关于MongoDB图片URL存储异常问题以及解决》:本文主要介绍关于MongoDB图片URL存储异常问题以及解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐... 目录MongoDB图片URL存储异常问题项目场景问题描述原因分析解决方案预防措施js总结MongoDB图

一文详解Java异常处理你都了解哪些知识

《一文详解Java异常处理你都了解哪些知识》:本文主要介绍Java异常处理的相关资料,包括异常的分类、捕获和处理异常的语法、常见的异常类型以及自定义异常的实现,文中通过代码介绍的非常详细,需要的朋... 目录前言一、什么是异常二、异常的分类2.1 受检异常2.2 非受检异常三、异常处理的语法3.1 try-

usb接口驱动异常问题常用解决方案

《usb接口驱动异常问题常用解决方案》当遇到USB接口驱动异常时,可以通过多种方法来解决,其中主要就包括重装USB控制器、禁用USB选择性暂停设置、更新或安装新的主板驱动等... usb接口驱动异常怎么办,USB接口驱动异常是常见问题,通常由驱动损坏、系统更新冲突、硬件故障或电源管理设置导致。以下是常用解决

将Java程序打包成EXE文件的实现方式

《将Java程序打包成EXE文件的实现方式》:本文主要介绍将Java程序打包成EXE文件的实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录如何将Java程序编程打包成EXE文件1.准备Java程序2.生成JAR包3.选择并安装打包工具4.配置Launch4

Linux命令之firewalld的用法

《Linux命令之firewalld的用法》:本文主要介绍Linux命令之firewalld的用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux命令之firewalld1、程序包2、启动firewalld3、配置文件4、firewalld规则定义的九大

Java程序进程起来了但是不打印日志的原因分析

《Java程序进程起来了但是不打印日志的原因分析》:本文主要介绍Java程序进程起来了但是不打印日志的原因分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Java程序进程起来了但是不打印日志的原因1、日志配置问题2、日志文件权限问题3、日志文件路径问题4、程序

Linux之计划任务和调度命令at/cron详解

《Linux之计划任务和调度命令at/cron详解》:本文主要介绍Linux之计划任务和调度命令at/cron的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux计划任务和调度命令at/cron一、计划任务二、命令{at}介绍三、命令语法及功能 :at

Linux下如何使用C++获取硬件信息

《Linux下如何使用C++获取硬件信息》这篇文章主要为大家详细介绍了如何使用C++实现获取CPU,主板,磁盘,BIOS信息等硬件信息,文中的示例代码讲解详细,感兴趣的小伙伴可以了解下... 目录方法获取CPU信息:读取"/proc/cpuinfo"文件获取磁盘信息:读取"/proc/diskstats"文

Linux内核参数配置与验证详细指南

《Linux内核参数配置与验证详细指南》在Linux系统运维和性能优化中,内核参数(sysctl)的配置至关重要,本文主要来聊聊如何配置与验证这些Linux内核参数,希望对大家有一定的帮助... 目录1. 引言2. 内核参数的作用3. 如何设置内核参数3.1 临时设置(重启失效)3.2 永久设置(重启仍生效

电脑死机无反应怎么强制重启? 一文读懂方法及注意事项

《电脑死机无反应怎么强制重启?一文读懂方法及注意事项》在日常使用电脑的过程中,我们难免会遇到电脑无法正常启动的情况,本文将详细介绍几种常见的电脑强制开机方法,并探讨在强制开机后应注意的事项,以及如何... 在日常生活和工作中,我们经常会遇到电脑突然无反应的情况,这时候强制重启就成了解决问题的“救命稻草”。那