segfault在什么时候发生?

时间:2009-06-01 15:58:41

标签: c segmentation-fault

以下代码是否在数组[10] = 22或数组[9999] = 22? 我只想弄清楚整个代码是否会在它出错之前执行。 (用C语言编写)。

#include <stdio.h>
int main(){

int array[10];
int i;
for(i=0; i<9999; ++i){
    array[i] = 22;
}    
return 0;    
}

8 个答案:

答案 0 :(得分:13)

这取决于...... 如果数组[9]之后的内存是干净的,那么可能不会发生任何事情,直到有一段内存到达被占用的内存段。

试用代码并添加:

 printf("%d\n",i);
循环中的

,你会看到它崩溃和烧伤的时间。 我得到了各种结果,范围从596到2380.

答案 1 :(得分:9)

使用debugger

$ gcc -g seg.c -o so_segfault
$ gdb so_segfault
GNU gdb 6.8-debian
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "i486-linux-gnu"...
(gdb) run
Starting program: /.../so_segfault 
Program received signal SIGSEGV, Segmentation fault.
0x080483b1 in main () at seg.c:7
7       array[i] = 22;
(gdb) print i
$1 = 2406
(gdb) 

实际上,如果再次运行它,您将看到对于相同的i值,并不总是会发生段错误。可以肯定的是,它发生在i&gt; = 10时,但是没有办法确定它将崩溃的i的值,因为这不是确定性的:它取决于内存的分配方式。如果内存是空闲的,直到数组[222](也就是没有其他程序使用它),它将一直持续到i = 222,但它也可能因为i> = 10的任何其他值而崩溃。

答案 2 :(得分:8)

答案可能是。 C语言说 nothing 关于在这种情况下应该发生什么。这是未定义的行为。编译器不需要检测问题,做任何事情来处理问题,终止程序或其他任何东西。所以什么也没做。

你写的不是你的记忆,在实践中可能会发生以下三种情况之一:

  • 你可能很幸运,只是得到一个段错误。如果您点击未分配给您的流程的地址,则会发生这种情况。操作系统会检测到这一点,并向您抛出错误。
  • 您可能会遇到真正未使用过的内存,在这种情况下马上就不会发生错误。但如果内存被分配并在以后使用,它将覆盖您的数据,如果您希望它仍然存在,那么您将获得一些不错的延迟操作错误。
  • 您可能会点击实际用于其他内容的数据。你需要覆盖它,有时很快,当需要原始数据时,它会读取你的数据,然后会发生不可预测的错误。

写出界限:就是不要这样做。 C语言在发生时不会告诉你什么,所以你必须自己关注它。

答案 3 :(得分:4)

您的代码崩溃的时间和方式不确定。它取决于您运行代码的平台。

array是一个堆栈变量,因此编译器将为堆栈保留10 * sizeof(int)个字节。根据编译器如何排列其他局部变量以及堆栈增长的方式,i可能会在array之后。如果您遵循Daniel的建议并将printf声明放入,您可能会注意到一个有趣的效果。在我的平台上,当i = 10array[10] = 22 clobbers i和下一个分配到array[23]时。

当用户代码尝试触摸无权访问的页面时,会发生分段违规。在这种情况下,如果您的堆栈足够小以至于9999次迭代从堆栈中耗尽,您将得到一个。

如果您已经在堆上分配了array(使用malloc()),那么当您运行页边界的末尾时,您将获得一个SIGSEGV。即使是10字节的分配也会返回整页。页面大小因平台而异。请注意,某些malloc调试器可以尝试标记数组越界的情况,但除非在您运行页面末尾时涉及硬件,否则您将无法获得SIGSEGV。

答案 4 :(得分:3)

你的代码段错误取决于你正在使用的编译器,运气和相关程序的其他链接细节。对于i == 10,您很可能段错误。即使它在您的阵列之外,您几乎肯定会在该位置为您的进程分配内存。但是,当您继续超出数组范围时,最终会将内存分配给您的进程,然后进行段错误。

但是,如果超出数组边界,则可能会覆盖同一堆栈帧中的其他自动变量。如果这些变量中的任何一个是指针(或稍后使用的数组索引),那么当您引用这些现在已损坏的值时,您可能会采用段错误。 (取决于损坏的确切值以及您现在是否要引用未分配给您的进程的内存。)

这不是非常确定的。

答案 5 :(得分:2)

访问进程外部专用内存时发生

分段错误, 这不容易预测。当i == 10时,它在数组之外......但可能仍然在进程的内存中。这取决于如何分配进程内存,无法(通常)知道(取决于操作系统的内存管理器)。因此,段错误可能发生在i = 10 - 9999中的任何一个,或者根本不发生。

答案 6 :(得分:0)

我建议使用GDB调查此类问题:http://www.gnu.org/software/gdb/documentation/

答案 7 :(得分:0)

更一般地说,您可以使用调试器找出Linux系统中发生分段故障的位置。例如,要使用gdb,请使用-g标志编译带有调试符号的程序,例如:

gcc -g segfault.c -o segfault

然后,使用--args标志,.g。:

使用您的程序和任何参数调用gdb
gdb --args ./segault myarg1 myarg2 ...

然后,当调试器启动时,键入run,程序应运行直到收到SIGSEGV,并且应该在收到该信号时告诉您它在源代码中的位置。