在rhel5.4上用GCC编程好长时间了(其实也就1个多月!),经常遇到这种情况:一个程序编译没有任何问题,当执行
./a.out的时候出现:“Segmentation fault(段错误)”,下面就是最近的一次情况(目的只是测试strcat函数):
#include<stdio.h>
25 #include<string.h>
26 int main()
27 {
28 char *str1 = "Wang";
29 char *str2 = "Lei";
30 printf("%s/n", strcat(str1, str2));
31 return 0;
32 }
(前面的数字只是标号,不是程序部分)。
编译运行:
[root@localhost C]# cc my_strcat.c
[root@localhost C]# ./a.out
Segmentation fault
于是开始查找信息,下面是查找的情况。(我把上面代码的调试放在了最后!是一个内存溢出的错误!)
=======================>8====================================================
(没经作者容许就剪贴过来了,在此表示歉意!)
1)往受到系统保护的内存地址写数据
有些内存是内核占用的或者是其他程序正在使用,为了保证系统正常工作,所以会受到系统的保护,而不能任意访问.
#include <stdio.h>
int
main()
{
int i = 0;
scanf ("%d", i); /* should have used &i */
printf ("%d/n", i);
return 0;
}
编译和执行一下, 咋一看,好像没有问题哦,不就是读取一个数据然后给输出来吗?
falcon@falcon:~/temp$ gcc -g -o segerr segerr.c –加-g选项查看调试信息
falcon@falcon:~/temp$ gdb ./segerr
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “i486-linux-gnu”…Using host libthread_db library “/ lib/tls/i686/cmov/libthread_db.so.1″.(gdb) l –用l(list)显示我们的源代码
1 #include <stdio.h>
2
3 int
4 main()
5 {
6 int i = 0;
7
8 scanf (”%d”, i); /* should have used &i */
9 printf (”%d/n”, i);
10 return 0;
(gdb) b 8 –用b(break)设置断点
Breakpoint 1 at 0×80483b7: file segerr.c, line 8.
(gdb) p i –用p(print)打印变量i的值[看到没,这里i的值是0哦]
$1 = 0(gdb) r –用r(run)运行,直到断点处
Starting program: /home/falcon/temp/segerrBreakpoint 1, main () at segerr.c:8
8 scanf (”%d”, i); /* should have used &i */ –[试图往地址0处写进一个值]
(gdb) n –用n(next)执行下一步
10Program received signal SIGSEGV, Segmentation fault.
0xb7e9a1ca in _IO_vfscanf () from /lib/tls/i686/cmov/libc.so.6
(gdb) c –在上面我们接收到了SIGSEGV,然后用c(continue)继续执行
Continuing.Program terminated with signal SIGSEGV, Segmentation fault.
The program no longer exists.
(gdb) quit –退出gdb
果然
我们“不小心”把&i写成了i
而我们刚开始初始化了i为0,这样我们不是试图向内存地址0存放一个值吗?
[补充:
可以通过man 7 signal查看SIGSEGV的信息。
falcon@falcon:~/temp$ man 7 signal | grep SEGV
Reformatting signal(7), please wait…
SIGSEGV 11 Core Invalid memory reference
例子2:
#include <stdio.h>
int
main()
{
char *p;
p = NULL;
*p = ‘x’;
printf(”%c”, *p);
return 0;
}
很容易发现,这个例子也是试图往内存地址0处写东西。
这里我们通过gdb来查看段错误所在的行
falcon@falcon:~/temp$ gcc -g -o segerr segerr.c
falcon@falcon:~/temp$ gdb ./segerr
GNU gdb 6.4-debian
Copyright 2005 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type “show copying” to see the conditions.
There is absolutely no warranty for GDB. Type “show warranty” for details.
This GDB was configured as “i486-linux-gnu”…Using host libthread_db library “/lib/tls/i686/cmov/libthread_db.so.1″.(gdb) r –直接运行,我们看到抛出段错误以后,自动显示出了出现段错误的行,这就是一个找出段错误的方法
Starting program: /home/falcon/temp/segerrProgram received signal SIGSEGV, Segmentation fault.
0×08048516 in main () at segerr.c:10
10 *p = ‘x’;
(gdb)
2)内存越界(数组越界