重新认识Segment fault

对于这个问题,只是之前听说过,并没有研究过。最近在oj编程时,vs上运行没有问题,提交时出现了段错误。为此重视一下这个问题。

在维基上给出这个名词的定义

A segmentation fault occurs when a program attempts to access a memory location that it is not allowed to access, or attempts to access a memory location in a way that is not allowed (for example, attempting to write to a read-onlylocation, or to overwrite part of the operating system).

所谓的段错误 就是指访问的内存超出了系统所给这个程序的内存空间,通常这个值是由gdtr来保存的,他是一个48位的寄存器,其中的32位是保存由它指向的gdt表, 后13位保存相应于gdt的下标,最后3位包括了程序是否在内存中以及程序的在cpu中的运行级别,指向的gdt是由以64位为一个单位的表,在这张表中 就保存着程序运行的代码段以及数据段的起始地址以及与此相应的段限和页面交换还有程序运行级别还有内存粒度等等的信息。一旦一个程序发生了越界访 问,cpu就会产生相应的异常保护,于是segmentation fault就出现了(来源网络)

关于一些理论的知识在此,就不叙述了,最后会给出一个博客链接,介绍。

接下来用小代码实验来说明一些问题

一、

#include<stdio.h>

int main()
{
 char* s= "hello";
 s[1]=‘h‘;

 return 0;
}

这段代码很明显是错误的,但是语法没有问题。在vs下编译通过。

然而这里会引起非法写,这里字符串既不是存放在栈也不是在堆里面,是在全局区中,或者说在代码段中,这段内存是不可写的,

vs在运行时出现下面的错误

Unhandled exception at 0x002f1398 in segdefault.exe: 0xC0000005: Access violation writing location 0x002f573d.

二、

#include<stdio.h>
int main()
{
 int* s=(int*)0xd000001;
 *s=1;
 return 0;
}

这段代码从语法上将是没有问题的,vs编译通过,但是有个明显的问题就是,指针指向了未知内存,或者说这是一个野指针,这段内存可能不是操作系统分配给当前进程的,所以操作系统也会产生异常。vs运行出现下面错误

Unhandled exception at 0x00b21398 in segdefault.exe: 0xC0000005: Access violation writing location 0x0d000001.

三、

#include<stdio.h>

int* f()
{
 int a=1;
 return &a;
}
int main()
{
 int* p;
 p=f();
 printf("%d\n",*p);
 return 0;
}

对于这段代码,vs在编译时有一个警告

warning C4172: returning address of local variable or temporary

即返回局部变量地址,也就是说f函数的栈在函数结束时会释放掉,如果返回此时栈里面的内容,实际是不可取的,

看看vs运行的结果

结果没有什么问题,或者说此时指针指向的是当前栈空间之外的区域,发生了栈溢出,但是有个问题就是,当一个函数结束时,他的栈是如何被回收的,

如果看到汇编知道,只是修改了esp这个指针,所以在下一次没有用这块空间栈时,里面的内容是还存在的。

四、

下面这个代码是网上看到的,用于测试堆

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

#define K 1024
int main()
{
 char* c;
 int i=0;

 c=(char*)malloc(1);
 while(1)
 {
  c+=K;
  *c=‘a‘;
  printf("overflow%dK\n",i);
  i++;
 }

 return 0;
}

这段代码在vs上运行是不通过,有下面的错误

Unhandled exception at 0x010c33f3 in segdefault.exe: 0xC0000005: Access violation writing location 0x00575208.

而在linux gcc平台下

编译通过并且可以运行,运行结果如下

也就是在堆中,如果一直溢出,当达到130k时就会产生段错误,这个跟os的内存分配有关,以后研究到linux内存分配时在具体找出原因。

五、

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

#define K 1024
int main()
{
 char* c;
 int i=0;

 c=(char*)malloc(1);
 *c=‘a‘;
 printf("%p\n",c);
 printf("%c\n",*c);
 free(c);
 printf("%p\n",c);
 printf("%c\n",*c);

 return 0;
}

这段代码实际测试的是free,free实现是怎么样的,

在linux中

也就是说,free之后,指向指针的地址并没有发生变化,还是指向那块堆空间,但是里面的内容变化了,

将堆中的内容以整数打印出来为

也就是说free之后将分配的堆空间清零了。

六、

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

void f()
{
 char c=‘a‘;
 memset(&c,0x55,128);
}
int main()
{
 f();
 printf("return ?\n");

 return 0;
}

这个问题在于在函数f中修改了栈空间的内容,因为在进入f之前main会压入f返回后要执行的指令的地址,这样将地址内容修改了,使得返回的是一个野指针。

vs出现下面的错误。

Unhandled exception at 0x55555555 in segdefault.exe: 0xC0000005: Access violation.

所有上面的情况其实认为都是尽量避免的,

在网上看到有人总结了如何小心避免

1、

其 它 程 序 员 不 同 的 是 , 彻 底 的 懂 得 你 的 程 序 。

指 做 到 精 确 控 制 。 尤 其 在 内 存 的 分 配 和 释 放 方 面 。 在 操 作 每 一 个 指 针 前 , 你 都 应 该 清 楚 它 所

向 内 存 的 出 处 ( 栈 、 堆 、 全 局 区 ) , 并 清 楚 此 内 存 的 生 存 周 期 。 只 有 明 白 的 使 用 内 存 , 才 能

的 产 生 。 S I G S E G V 最 大 限 度 的 避免。

2、

大量使用assert,用于检查

3、多关注编译时产生的warning

资料链接

http://blog.csdn.net/jk110333/article/details/19685127(段错误调试)

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-13 04:17:59

重新认识Segment fault的相关文章

C语言 segment fault

Segmentation fault is a specific kind of error caused by accessing memory that “does not belong to you.” It’s a helper mechanism that keeps you from corrupting the memory and introducing hard-to-debug memory bugs. Whenever you get a segfault you know

利用linux信号机制调试段错误(Segment fault)

在实际开发过程中,大家可能会遇到段错误的问题,虽然是个老问题,但是其带来的隐患是极大的,只要出现一次,程序立即崩溃中止.如果程序运行在PC中,segment fault的调试相对比较方便,因为可以通过串口.显示器可以查看消息,只要程序运行,通过GDB调试工具即可捕捉产生segment fault的具体原因.但是不知大家有没有想法,当程序运行在嵌入式设备上时,你所面临资源的缺乏,你没有串口打印信息,没有显示器可查看,你不知道程序运行的状态,如果程序的产生segment falut这种bug发生的周

出现segment fault 错误的几种原因

segment fault 段异常各种原因www.MyException.Cn 发布于:2012-11-26 11:48:50 浏览:24次 0 segment fault 段错误各种原因一 造成segment fault,产生core dump的可能原因1.内存访问越界 a) 由于使用错误的下标,导致数组访问越界 b) 搜索字符串时,依靠字符串结束符来判断字符串是否结束,但是字符串没有正常的使用结束符 c) 使用strcpy, strcat, sprintf, strcmp, strcasec

Segment fault及LINUX core dump详解

源自:http://andyniu.iteye.com/blog/1965571 core dump的概念: A core dump is the recorded state of the working memory of a computer program at a specific time, generally when the program has terminated abnormally (crashed). In practice, other key pieces of

Segment fault及LINUX core dump详解 (zz)

C 程序在进行中发生segment fault(core dump)错误,通常与内存操作不当有关,主要有以下几种情况: (1)数组越界. (2)修改了只读内存. (3)scanf("%d",n),n不是指针. …… 1. 前言: 有的程序可以通过编译, 但在运行时会出现Segment fault(段错误). 这通常都是指针错误引起的. 但这不像编译错误一样会提示到文件->行, 而是没有任何信息, 使得我们的调试变得困难起来. 2. gdb: 有一种办法是, 我们用gdb的step

一次php脚本出现段错误(Segment fault)的经历

今天在一台新服务器上cli运行一个php脚本,出现了Segment fault错误,第一感觉应该是某个扩展安装有问题 这段php代码是调用soap接口,查看soap扩展没啥问题,一时不知道是啥原因. 想到可以用gdb调试core文件,于是去安装了一下gdb  ,并执行以下命令:ulimit -c unlimited 再次执行果然产生了core.PID文件,用gdb php路径 core.PID提示没有调试信息. 这.... 问了三金锅,原来php编译的时候需要带上 --debug才行. 于是重新

段错误Segment Fault定位,即core dump文件与gdb定位

使用C++开发系统有时会出现段错误,即Segment Fault.此类错误程序直接崩溃,通常没有任何有用信息输出,很难定位bug,因而无从解决问题.今天我们介绍core dump文件,并使用gdb进行调试,以此来定位段错误问题.此文同时用以备忘. 一.core dump Core dump也称核心转储, 当程序运行过程中异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 称之为core dump文件. 系统默认不生成core dump文件,可以使用ulimit命令进行查看和设

【Z】段错误Segment Fault定位,即core dump文件与gdb定位

使用C++开发系统有时会出现段错误,即Segment Fault.此类错误程序直接崩溃,通常没有任何有用信息输出,很难定位bug,因而无从解决问题.今天我们介绍core dump文件,并使用gdb进行调试,以此来定位段错误问题.此文同时用以备忘. 一.core dump Core dump也称核心转储, 当程序运行过程中异常退出时, 由操作系统把程序当前的内存状况存储在一个core文件中, 称之为core dump文件. 系统默认不生成core dump文件,可以使用ulimit命令进行查看和设

关于Release下没有问题,Debug下出现Segment Fault

前言: 在项目开发中出现Release下跑程序没有问题,Debug下出现Segment Fault. 代码如下: void fun(int lines){ int* pA; if(pA==nullptr){ pA=new int[lines]; } memset(pA,0,sizeof(int)*lines); //Segment Fault } 原因: Debug下局部变量中指针没有初始化,而编译器给了pA一个随机值,导致在if判断的时候跳出语句块,没有成功new内存,而在后面进行memset

Segment Fault 的访问地址究竟在哪里?

如果指针写数据失败, 比如 *p = 1 可以进一步看, 究竟为何失败 可以用察看  /proc/{pid}/maps, 但往往这个时候,程序已经crash 了,就找不到这个文件. 那就只能在crash 之前code 插入代码看了. 写一个copyfile 的函数 static void copyfile(char * rfile, char * wfile) { int rfd, wfd,size; rfd=open(rfile,O_RDONLY); wfd=open(wfile,O_WRON