段错误(核心已转储)的缘由

1、什么是段错误?

一旦一个程序发生了越界访问,cpu 就会产生相应的保护,因而 segmentation fault 就出现了,经过上面的解释,段错误应该就是访问了不可访问的内存,这个内存区要么是不存在的,要么是受到系统保护的,还有多是缺乏文件或者文件损坏。c++

2、段错误产生的缘由

下面是一些典型的段错误的缘由: 非关联化空指针——这是特殊状况由内存管理硬件 试图访问一个不存在的内存地址(在进程的地址空间) 试图访问内存的程序没有权利(如内核结构流程上下文) 试图写入只读存储器(如代码段)web

一、访问不存在的内存地址

在C代码,分割错误一般发生因为指针的错误使用,特别是在C动态内存分配。非关联化一个空指针老是致使段错误,但野指针和悬空指针指向的内存,可能会或可能不会存在,并且可能或不多是可读的仍是可写的,所以会致使瞬态错误。数组

#include <stdio.h>
 
int main (void) { int *ptr = NULL; *ptr = 0; return 0; } 输出结果: 段错误(核心已转储)

如今,非关联化这些变量可能致使段错误:非关联化空指针一般会致使段错误,阅读时从野指针可能致使随机数据但没有段错误,和阅读从悬空指针可能致使有效数据,而后随机数据覆盖。app

二、访问系统保护的内存地址 

#include <stdio.h>
 
int main (void) { int *ptr = (int *)0; *ptr = 100; return 0; } 输出结果: 段错误(核心已转储)

三、访问只读的内存地址

写入只读存储器提出了一个 segmentation fault,这个发生在程序写入本身的一部分代码段或者是只读的数据段,这些都是由操做系统加载到只读存储器。优化

#include <stdio.h> #include <string.h>
 
int main (void) { char *ptr = "test"; strcpy (ptr, "TEST"); return 0; } 输出结果: 段错误(核心已转储)
#include <stdio.h>
 
int main (void) { char *ptr = "hello"; *ptr = 'H'; return 0; } 输出结果: 段错误(核心已转储)

上述例子ANSI C代码一般会致使段错误和内存保护平台。spa

它试图修改一个字符串文字,这是根据ANSI C标准未定义的行为。操作系统

大多数编译器在编译时不会抓,而是编译这个可执行代码,将崩溃。.net

包含这个代码被编译程序时,字符串“hello”位于rodata部分程序的可执行文件的只读部分数据段。unix

当加载时,操做系统与其余字符串和地方常数只读段的内存中的数据。指针

当执行时,一个变量 ptr 设置为指向字符串的位置,并试图编写一个H字符经过变量进入内存,致使段错误。

编译程序的编译器不检查做业的只读的位置在编译时,和运行类unix操做系统产生如下运行时发生 segmentation fault。

#include <stdio.h>
 
int main (void) { char ptr[] = "hello"; ptr[0] = 'H'; return 0; }

即便不能修改字符串(相反,这在C标准未定义行为),在C char *类型,因此没有隐式转换原始代码,在c++的 const char *类型,所以有一个隐式转换,因此编译器一般会抓住这个特定的错误。

四、空指针废弃

由于是一个很常见的程序错误空指针废弃(读或写在一个空指针,用于C的意思是“没有对象指针”做为一个错误指示器),大多数操做系统内存访问空指针的地址,这样它会致使段错误。

#include <stdio.h>
 
int main (void) { int *ptr = NULL; printf ("%d\n", *ptr); return 0; } 输出结果: 段错误(核心已转储)

这个示例代码建立了一个空指针,而后试图访问它的值(读值)。在运行时在许多操做系统中,这样作会致使段错误。

非关联化一个空指针,而后分配(写一个值到一个不存在的目标)也一般会致使段错误。

 

#include <stdio.h>
 
int main (void) { int *ptr = NULL; *ptr = 1; return 0; } 输出结果: 段错误(核心已转储)

下面的代码包含一个空指针,但当编译一般不会致使段错误,值是未使用的。所以,废弃一般会被优化掉,死代码消除。

#include <stdio.h>
 
int main (void) { int *ptr = NULL; *ptr; return 0; }

还有,好比malloc 动态分配内存,释放、置空完成后,不可再使用该指针。

#include <stdio.h> #include <stdlib.h> #include <string.h>
 
int main() { char* str=(char* )malloc(100); if(*str) { return; } strcpy(str,"hello"); printf("%s\n",str); free(str); str=NULL; strcpy(str,"abcdef"); return 0; } 输出结果: hello 段错误 (核心已转储)

五、堆栈溢出

#include <stdio.h> #include <string.h>
 
int main (void) { main (); return 0; } 输出结果: 段错误(核心已转储)

上述例子的无限递归,致使的堆栈溢出会致使段错误,但无线递归未必致使堆栈溢出,优化执行的编译器和代码的确切结构。

在这种状况下,高不可攀的代码(返回语句)行为是未定义的。

所以,编译器能够消除它,使用尾部调用优化,可能致使没有堆栈使用。其余优化可能包括将递归转换成迭代,给出例子的结构功能永远会致使程序运行,虽然可能不是其余堆栈溢出。

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

#include <stdio.h>
 
int main (void) { char test[10]; printf ("%c\n", test[100000]); return 0; } 输出结果: 段错误(核心已转储)

 

转自:

--------------------- 做者:聚优致成 来源:CSDN 原文:https://blog.csdn.net/qq_29350001/article/details/53780697

相关文章
相关标签/搜索