GDB调试Segmentation Fault

http://www.unknownroad.com/rtfm/gdbtut/gdbsegfault.html

7.2 Example Debugging Session: Segmentation Fault Example

We are going to use gdb to figure out why the following program causes a segmentation fault. The program is meant to read in a line of text from the user and print it. However, we will see that in it's current state it doesn't work as expected...

1 : #include <stdio.h> 2 : #include <stdlib.h> 3 : int main(int argc, char **argv) 4 : { 5 : char *buf; 6 : 7 : buf = malloc(1<<31); 8 : 9 : fgets(buf, 1024, stdin); 10: printf("%s\n", buf); 11: 12: return 1; 13: }


The first step is to compile the program with debugging flags:

prompt> gcc -g segfault.c

Now we run the program:

prompt > a.out Hello World! Segmentation fault prompt >

This is not what we want. Time to fire up gdb:

prompt > gdb a.out GNU gdb 5.0 Copyright 2000 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 "i686-pc-linux-gnu"... (gdb)

We'll just run it and see what happens:

(gdb) run Starting program: /home/dgawd/cpsc/363/a.out test string Program received signal SIGSEGV, Segmentation fault. 0x4007fc13 in _IO_getline_info () from /lib/libc.so.6

So we received the SIGSEGV signal from the operating system. This means that we tried to access an invalid memory address. Let's take a backtrace:

(gdb) backtrace #0 0x4007fc13 in _IO_getline_info () from /lib/libc.so.6 #1 0x4007fb6c in _IO_getline () from /lib/libc.so.6 #2 0x4007ef51 in fgets () from /lib/libc.so.6 #3 0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10 #4 0x40037f5c in __libc_start_main () from /lib/libc.so.6

We are only interested in our own code here, so we want to switch to stack frame 3 and see where the program crashed:

(gdb) frame 3 #3 0x80484b2 in main (argc=1, argv=0xbffffaf4) at segfault.c:10 10 fgets(buf, 1024, stdin)

We crashed inside the call to fgets. In general, we can assume that library functions such as fgets work properly (if this isn't the case, we are in a lot of trouble). So the problem must be one of our arguments. You may not know that 'stdin' is a global variable that is created by the stdio libraries. So we can assume this one is ok. That leaves us with 'buf':

(gdb) print buf $1 = 0x0

The value of buf is 0x0, which is the NULL pointer. This is not what we want - buf should point to the memory we allocated on line 8. So we're going to have to find out what happened there. First we want to kill the currently-running invocation of our program:

(gdb) kill Kill the program being debugged? (y or n) y

Now set a breakpoint on line 8:

(gdb) break segfault.c:8 Breakpoint 1 at 0x8048486: file segfault.c, line 8.

Now run the program again:

(gdb) run Starting program: /home/dgawd/cpsc/363/a.out Breakpoint 1, main (argc=1, argv=0xbffffaf4) at segfault.c:8 8 buf = malloc(1<<31);

We're going to check the value of buf before the malloc call. Since buf wasn't initialized, the value should be garbage, and it is:

(gdb) print buf $2 = 0xbffffaa8 "Čúĸŋ#\177\003@t`\001@\001"

Now step over the malloc call and examine buf again:

(gdb) next 10 fgets(buf, 1024, stdin); (gdb) print buf $3 = 0x0

After the call to malloc, buf is NULL. If you were to go check the man page for malloc, you would discover that malloc returns NULL when it cannot allocate the amount of memory requested. So our malloc must have failed. Let's go back and look at it again:

7 : buf = malloc(1<<31);

Well, the value of the expression 1 << 31 (the integer 1 right-shifted 31 times) is 429497295, or 4GB (gigabytes). Very few machines have this kind of memory - mine only has 256MB. So of cousre malloc would fail. Furthermore, we are only reading in 1024 bytes in the fgets call. All that extra space would be wasted, even if we could allocate it. Change the 1<<31 to 1024 (or 1<<9), and the program will work as expected:

prompt > Hello World! Hello World! prompt >

So now you know how to debug segmentation faults with gdb. This is extremely useful (I use it more often then I care to admit). The example also illustrated another very important point: ALWAYS CHECK THE RETURN VALUE OF MALLOC! Have a nice day.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏ml

cf------(round)#1 B. Spreadsheets(模拟)

B. Spreadsheets time limit per test 10 seconds memory limit per test 64 mega...

28850
来自专栏SpringBoot

springboot + jpa + redis + hibernate validator + 后台抽象

项目码云地址:https://gitee.com/DencyCheng/admin-api

27410
来自专栏算法修养

CodeForces 667A Pouring Rain

A. Pouring Rain time limit per test 1 second memory limit per test 256 meg...

29450
来自专栏指尖下的Android

OkHttp's NullPointerException in HttpUrl.class

今天测试在小米5.0-6.0的机型中测试发现一个空指针的异常,经过排查后发现OkHttp的请求参数不能为null,这个请求接口会上传当前机型的手机号、ip地址和...

50520
来自专栏Ryan Miao

SpringMVC中@RequestBody引起的400异常处理,返回校验失败具体信息

问题 使用@RequestBody接收一个json数据的时候,如果传入的参数不符合条件,就会直接返回400的error page. 但究竟是为什么会400并没有...

51070
来自专栏编程坑太多

JAVA实现Excel导入导出

51830
来自专栏小筱月

controller层中,参数的获取方式以及作用域的问题

16330
来自专栏一个会写诗的程序员的博客

《Springboot极简教程》@EnableMongoRepositories路径配置:APPLICATION FAILED TO START: Parameter 0 of constructor

Parameter 0 of constructor in com.restfeel.controller.BlogController required a ...

11440
来自专栏SAP最佳业务实践

SAP最佳业务实践:SD–带变式价格的销售报价(663)-4创建订单

一、 VA01 Deriving Order from Follow-On Quotation Aftercomparing various quotation...

36960
来自专栏算法修养

PAT 1016 Phone Bills(模拟)

1016. Phone Bills (25) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题...

44670

扫码关注云+社区

领取腾讯云代金券