什么导致 SIGSEGV
Posted
技术标签:
【中文标题】什么导致 SIGSEGV【英文标题】:What causes a SIGSEGV 【发布时间】:2010-12-06 13:38:25 【问题描述】:我需要知道分段错误(SIGSEGV)的根本原因,以及如何处理它。
【问题讨论】:
@GMan - 根本原因可能是对指针的理解草率。没有说任何关于 OP 的事情——可能不是他的代码——只是有人不知道如何正确使用指针。 【参考方案1】:当您访问程序未声明的内存时,会出现分段错误。你可以通过指针来做到这一点,即通过内存地址。或者这也可能是由于***,例如:
void rec_func() int q = 5; rec_func();
int main() rec_func();
此调用将继续消耗堆栈内存,直到它完全填满,因此最终发生堆栈溢出。 注意:它可能在一些竞争性问题中不可见,因为它首先会导致 timeouterror,但对于那些没有发生超时的问题,很难弄清楚 SIGSEGV。
【讨论】:
【参考方案2】:最初的根源也可能是内存不足。
【讨论】:
我试图找到更多关于这方面的信息,但没有取得多大成功。我的猜测是,如果进程已经分配了一些大块内存并且启用了过量使用,一旦你开始写入,内核将寻找物理内存,如果失败,你会得到分段错误。是这样吗? 我认为简单地尝试分配你物理上没有的内存,或者超出沙箱的限制,会导致程序某处崩溃或引发 SIGSEGV。【参考方案3】:SigSegV 表示内存访问违规的信号,试图读取或写入您的进程无权访问的内存区域。这些不是 C 或 C++ 异常,您无法捕获信号。确实可以编写一个忽略问题并允许在未定义状态下继续执行不稳定程序的信号处理程序,但显然这是一个非常糟糕的主意。
大多数时候这是因为程序中的错误。给出的内存地址可以帮助调试问题所在(如果它接近于零,则可能是空指针取消引用,如果地址类似于 0xadcedfe,则它是故意保护或调试检查等)
“捕获”信号的一种方法是在单独的子进程中运行您的东西,然后该子进程可以突然终止,而不会随之关闭您的主进程。找到根本原因并解决它显然比这样的解决方法更可取。
【讨论】:
【参考方案4】:分段错误有多种原因,但从根本上说,您正在错误地访问内存。这可能是由于取消引用空指针,或尝试修改只读内存,或使用指向未映射到进程内存空间的某个位置的指针(这可能意味着您正在尝试使用数字作为指针) ,或者您将指针增加得太远)。在某些机器上,通过指针的未对齐访问也可能导致问题 - 例如,如果您有一个奇数地址并尝试从中读取偶数个字节(相反,它可以生成 SIGBUS)。
【讨论】:
这里的不同错误信号定义不明确 - 在 OS X 上,char *c = NULL; *c;
实际上生成的是 SIGBUS 而不是 SIGSEGV。
是的 - SIGBUS 和 SIGSEGV 在某种程度上都是系统和/或处理器特定的。两者都意味着你在滥用内存。两者都不健康。【参考方案5】:
这是一个 SIGSEGV 的例子。
root@pierr-desktop:/opt/playGround# cat test.c
int main()
int * p ;
* p = 0x1234;
return 0 ;
root@pierr-desktop:/opt/playGround# g++ -o test test.c
root@pierr-desktop:/opt/playGround# ./test
Segmentation fault
这里是detail。
如何处理?
尽量避免 第一名。
防御性编程:使用assert(),检查NULL指针,检查缓冲区溢出。
使用静态分析工具检查您的代码。
使用 -Werror -Wall 编译您的代码。
有人审查你的代码。
那是什么时候发生的。
仔细检查您的代码。
检查自上次代码成功运行且未崩溃后所做的更改。
希望 gdb 会给你一个调用堆栈,以便你知道崩溃发生在哪里。
编辑:抱歉匆忙。应该是*p = 0x1234;
而不是p = 0x1234
;
【讨论】:
为什么要给一个指针分配一个无效值而不是取消引用该指针 SIGSEGV? 这个程序不能用任何 C++ 编译器编译。如果添加必要的强制转换,它就不会崩溃,因为它实际上没有任何无效的内存访问。 严格来说,强制将任意值放入指针对象可能会导致 C/C++ 程序立即崩溃,而无需尝试取消引用(阅读“陷阱表示”),但这并不是最常见的我们当中很可能在实践中遇到。当然,这不是说明 SIGSEGV 的好例子 :) 每当我遇到段错误时,我都会使用经典的printf()
方法进行调试,慢慢找出问题所在。 (实际上,puts()
可能是为此目的最好的函数,因为它会自动添加换行符,从而自动刷新输出。但有时我也需要打印出变量值。)【参考方案6】:
Wikipedia 有答案,还有许多其他来源。
段错误基本上意味着您对指针做了坏事。这可能是一个段错误:
char *c = NULL;
...
*c; // dereferencing a NULL pointer
或者这个:
char *c = "Hello";
...
c[10] = 'z'; // out of bounds, or in this case, writing into read-only memory
或者这样:
char *c = new char[10];
...
delete [] c;
...
c[2] = 'z'; // accessing freed memory
每种情况下的基本原则相同 - 你正在用不属于你的记忆做某事。
【讨论】:
【参考方案7】:使用无效/空指针?超出数组的边界?没有任何示例代码很难具体说明。
本质上,您正在尝试访问不属于您的程序的内存,因此操作系统将其杀死。
【讨论】:
以上是关于什么导致 SIGSEGV的主要内容,如果未能解决你的问题,请参考以下文章