Linux 下 segmentation fault(段错误) 总结

在LIinux 下C/C++中,出现段错误很多都是有指针造成的,指针声明后没有内容的存储空间,当你不指向指定的内存空间时,就会出现segmentation fault(段错误),这种情况往往能编译通过的,但是运行时就会出现在段错误。

段错误segmentation fault,信号SIGSEGV,是由于访问内存管理单元MMU异常所致,通常由于无效内存引用,如指针引用了一个不属于当前进程地址空间中的地址,操作系统便会进行干涉引发SIGSEGV信号产生段错误。

段错误产生的原因

空指针
野指针
堆栈越界

空指针

由于空指针访问导致段错误是较为常见和简单的一种,空指针访问即尝试操作地址为0的内存区域,由于该区域内存是禁止访问的区域,所以当发生空指针访问时进程就会收到SIGSEGV信号发生Segmentation fault例如:

#include <stdio.h>

int main(int argc, char* argv[])
{
    int* ptr = NULL;
    *ptr = 0;
    
    return 0;
}

编译运行:

在这里插入图片描述

恭喜,出现段错误了!

通常在项目中的遇到的空指针大多在对象访问的时候出现,一般情况下是对对象的方法进行访问,所以即使对象指针为空也不会马上出现段错误,只有当访问对象数据成员是才可能发生段错误。

野指针

野指针通常有两种情况,一种是指针未初始化,指针定义后是不会自动初始化为NULL指针,它的缺省值是随机的,所以指针定义的时候就应该初始化为NULL或者合法内存;第二种是指向的内存已经释放,使用free或者delete操作并不会对指针本身进行清除,释放完后应该对指针进行重置,或者指向的对象已经超出了对象作用域范围,离开作用域的时候也应该对指针进行重置;

#include <stdio.h>
#include <string.h>


int main(int argc , char *argv[])
{
	char *source1 = "abc";
	char *source2;
	
	printf("first source2 is : %u\n",source2);
	strcpy(source2,source1);
	printf("second source2 is : %s\n");
	
	return 0;
}

编译输出:

在这里插入图片描述
这段程序定义了一个指向字符的指针source2,但是没有给它一个初始值。由于source2在定义时没有给初值,程序运行时系统会默认给source2一个值(732373280),而732373280是一个内存的地址,至于是哪段内存地址,谁也不知道,可能是操作系统本身所在的内存地址,也可能是一个空的内存地址。

野指针是危险的因为它不像空指针一样可以通过判断来识别是否指向合法内存,它可能指向一块不存在的内存页,也可能是指向一块没有访问权限的内存区域,如果是这样你应该感谢segmentation fault段错误,因为问题很快就会暴露出来而不会被蔓延,否则如果指向了一块合法内存,那对内存的破坏将会有无法预测的事情发生,可能只是纂改了你的数据,也可能是破坏了内存结构,这个时候错误可能被蔓延到一个无法预测的时刻。

堆栈越界

堆栈越界通常分为堆越界和栈越界。

堆越界破坏的是堆内存空间,堆空间通常由malloc/new分配,free/delete进行回收,由于堆内存空间分配的时候并不一定是连续的,所以如果发生堆越界可能破坏的内存属于一个毫无关系的对象,堆越界通常都会破坏堆内存结构,导致后续分配或者回收内存的时候出现异常。

#include <stdio.h>
#include <stdlib.h>
#include <string.h> 

int main(int argc ,char *argv[])
{

	char *p=(char *)malloc(sizeof(char)*10);
	char *q=strcpy(p,"This is an example of a heap error");
	
	free(p);	
	return 0;
}


编译运行:
在这里插入图片描述
分配的堆空间为10个byte。多出来的字符被放置在10之后的内存中。一不小心发生了越界。才出现了这个堆被破坏的错误。

栈越界破坏的栈内存空间,栈空间是由系统自动分配和回收,栈空间分配是从高地址象低地址连续分配的,所以当出现栈越界破坏的都是相邻的数据块,栈越界通常修改当前函数返回地址,参数或者局部变量,如果返回地址被修改可能会产生指令错误或者执行非预期的代码,所以黑客通常通过栈越界来插入后门。

#include <stdio.h>
#include <string.h>
#include <stdbool.h>

bool fun1()
{
    char passwd[10];
    printf("please input your password :\n");
    scanf("%s", passwd);
    printf("your password is %s\n", passwd);
    return true;
}
int main()
{
    if(fun1())
    {
        printf("ok!\n");
        return 0;
    }
    return 0;

}

编译运行:
在这里插入图片描述
如果程序崩溃出现栈破坏的情况,请检查数组越界、返回局部变量地址等等问题。在开发软件时一定要养成好习惯,不要犯这种错误,一般这种错误时很难定位的。

段错误信息的获取

dmesg命令

‘dmesg’命令显示linux内核的环形缓冲区信息,我们可以从中获得诸如系统架构、cpu、挂载的硬件,RAM等多个运行级别的大量的系统信息。

当计算机启动时,系统内核(操作系统的核心部分)将会被加载到内存中。在加载的过程中会显示很多的信息,在这些信息中我们可以看到内核检测硬件设备。

在这里插入图片描述可以看出,发生段错误的地址:0, 和指令指针地址:00000000004004e4

catchsegv工具

这里通过catchsegv 脚本测试段错误的方法,其他方法见后面相关资料。

catchsegv 利用系统动态链接的 PRELOAD 机制(请参考man ld-linux)

man ld-linux

在这里插入图片描述

把库 /lib/libSegFault.so 提前 load 到内存中,然后通过它检查程序运行过程中的段错误。

gdb + core

这种方式也很常用,关于gdb是linux下一个强大的debug调试程序,不熟的朋友可以参考这一篇<Linux 下Coredump分析与配置>,这里就不多说了

总结

我们在用C/C++语言写程序的时侯,内存管理的绝大部分工作都是需要我们来做的。实际上,内存管理是一个比较繁琐的工作,无论你多高明,经验多丰富,难免会在此处犯些小错误,而通常这些错误又是那么的浅显而易于消除。

有条件的情况尽量借助工具对问题进行排查定位包括用于单元测试,Linux平台推荐valgrind、catchsegv等。

Linux 下 segmentation fault(段错误) 总结_linux segmentation fault-CSDN博客

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Linux Qt中的"Segmentation fault"是一种常见的错误,它通常意味着程序访问了一个未分配或不可访问的内存地址,导致程序崩溃。这个错误通常由以下原因引起: 1. 内存访问错误:当程序试图访问未分配的内存或者已经被释放的内存时,就会发生这种错误。这可能是由于对已被删除或不存在的指针进行解引用,或者数组越界访问造成的。 2. 多线程同步问题:如果多个线程同时访问和修改同一个共享数据,而缺乏合适的同步机制可能导致内存访问错误。这种情况下,需要使用互斥锁、条件变量等来确保多个线程之间的正确同步。 3. 引用空指针:在使用指针时,如果没有将其初始化为有效的内存地址,或者直接引用了一个空指针,就会导致Segmentation fault错误。 4. 函数调用错误:如果函数调用参数的类型和期望的类型不符合,也有可能导致该错误。比如,传递了一个空指针给一个期望指针类型的函数。 当程序遇到Segmentation fault错误时,可以通过调试工具如gdb来确定出错的位置,并查看栈回溯信息以了解该错误的原因。通常,修复这种错误需要仔细检查代码,查找并修复潜在的内存访问问题和线程同步错误。 总之,Segmentation fault错误是Linux Qt开发中常见的错误之一,通常由内存访问错误、线程同步问题、引用空指针和函数调用错误引起。定位并修复这种错误需要仔细检查代码并尽可能遵循良好的编程实践。 ### 回答2: 当在Linux上使用Qt并遇到"segmentation fault"错误时,通常是由于以下几个常见原因之一导致的。 1. 内存错误:"segmentation fault"通常表示访问了未分配或已释放的内存区域。可能是由于代码(例如指针操作)中的错误导致的。检查代码中的内存分配和释放操作,确保没有错误。 2. 非法指针操作:使用了一个无效的指针,例如使用了已经释放的指针或空指针。这可能是由于代码中的逻辑错误导致的。检查代码中的指针操作,确保所有使用的指针都是有效的。 3. 依赖问题:Qt应用程序可能依赖于其他库或动态链接库。如果这些库的版本不匹配或缺失,也可能会导致"segmentation fault"错误。确保所有的依赖库都正确安装并且与Qt版本兼容。 4. 资源耗尽:如果应用程序使用了大量的内存或其他系统资源,在资源耗尽的情况下也可能导致"segmentation fault"错误。这可能包括内存、文件句柄、网络连接等资源。如果这是问题的原因,可以尝试优化资源使用或增加系统资源限制。 为了解决此错误,可以采取以下措施: 1. 使用调试器:通过在调试器中运行应用程序,可以获得更详细的错误信息,并定位到导致错误的代码行。通过这种方式,可以更容易地解决问题。 2. 添加错误检查:在可能导致错误的代码段添加适当的错误检查,以确保不会访问无效的内存或指针。 3. 更新和安装依赖:确保所有依赖库和Qt版本都是最新的,并且彼此兼容。 4. 优化资源使用:如果问题由于资源耗尽导致,可尝试优化代码以减少资源使用量。 总之,在解决"segmentation fault"错误时,关键是仔细检查代码,并使用适当的工具和技术来定位问题所在,并采取适当的措施解决问题。 ### 回答3: 当在Linux环境下使用Qt开发应用程序时,可能会遇到"segmentation fault"(段错误)的错误提示。这通常是由于程序在访问一个非法的内存地址或者试图对只读内存进行写入操作引起的。这种错误通常是由于编程错误造成的。 出现"segmentation fault"错误的原因有很多种,常见的包括: 1. 野指针或空指针:当程序试图访问一个未初始化的指针或已经释放的内存区域时,就会导致段错误的发生。 2. 内存越界:当程序试图访问一个超出分配给它的内存范围的地址时,会引发段错误。 3. 缓冲区溢出:当程序试图向一个长度不足的缓冲区写入数据时,可能会覆盖到其他内存区域,从而导致段错误。 4. 递归调用栈溢出:当程序递归调用的次数过多时,会导致调用栈溢出,从而引发段错误。 5. 动态库问题:当程序链接的动态库版本不兼容或缺失时,也可能导致段错误。 要解决"segmentation fault"错误,需要通过调试工具(如gdb)找到错误的具体位置,然后根据错误信息进行定位和修复。常见的修复方法包括: 1. 检查指针是否为NULL或已被释放。 2. 检查数组下标是否越界。 3. 检查对内存的操作是否合法。 4. 检查递归调用是否存在无限循环的情况。 5. 检查动态链接库的版本和兼容性。 总之,"segmentation fault"错误通常是由于编程错误引起的,要解决这个问题,需要仔细检查代码并进行逐步调试,找出错误的原因并进行修复。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值