GDB调试学习(四):段错误

简介: GDB调试学习(四):段错误

如果程序运行时出现段错误,用gdb可以很容易定位到究竟是哪一行引发的段错误,例如这个小程序:

实例一:

#include <stdio.h>
      int main(void)
      {
              int man = 0;
              scanf("%d", man);
              return 0;
      }

调试过程如下:

$ gdb main
      ...
      (gdb) r
      Starting program: /home/akaedu/main
      123
      Program received signal SIGSEGV, Segmentation fault.
      0x00175ed7 in _IO_vfscanf () from /lib/tls/i686/cmov/libc.so.6
      (gdb) bt
      #0  0x00175ed7 in _IO_vfscanf () from /lib/tls/i686/cmov/libc.so.6
      #1 0x0017caa9 in __isoc99_scanf () from /lib/tls/i686/cmov/libc.so. 6
      #2  0x0804842a in main () at main.c:6

在gdb中运行,遇到段错误会自动停下来,这时可以用命令查看当前执行到哪一行代码了。gdb显示段错误出现在_IO_vfscanf函数中,用bt命令可以看到这个函数是被main.c的第6行间接调用的,也就是scanf这行代码引发的段错误。仔细观察程序发现是man前面少了个&。

继续调试上一节的程序,上一节最后提出修正Bug的方法是在循环中加上判断条件,如果不是数字就报错退出,不仅输入字母可以报错退出,输入超长的字符串也会报错退出。

表面上看这个程序无论怎么运行都不出错了,但假如我们把while (1)循环去掉,每次执行程序只转换一个数:

实例二:

#include <stdio.h>
      int main(void)
      {
              int sum = 0, i = 0;
              char input[5];
              scanf("%s", input);
              for (i = 0; input[i] != '\0'; i++) {
                      if (input[i] < '0' || input[i] > '9') {
                              printf("Invalid input!\n");
                              sum = -1;
                              break;
                      }
                      sum = sum*10 + input[i] - '0';
              }
              printf("input=%d\n", sum);
              return 0;
      }

然后输入一个超长的字符串,看看会发生什么:

$ ./main
      1234567890
      Invalid input!
      input=-1

看起来正常。再来一次,这次输个更长的:

$ ./main
      1234567890abcdef1234567890abcdef
      Invalid input!
      input=-1
      Segmentation fault

又出段错误了。我们按照同样的方法用gdb调试看看:

$ gdb main
      ...
      (gdb) r
      Starting program: /home/akaedu/main
      1234567890abcdef1234567890abcdef
      Invalid input!
      input=-1
      Program received signal SIGSEGV, Segmentation fault.
      0x0804852e in main () at main.c:19
      19      }
      (gdb) l
      14                      }
      15                      sum = sum*10 + input[i] - '0';
      16              }
      17              printf("input=%d\n", sum);
      18              return 0;
      19      }

gdb指出,段错误发生在第19行。可是这一行什么都没有啊,只有表示main函数结束的}括号。

这可以算是一条规律,如果某个函数的局部变量发生访问越界,有可能并不立即产生段错误,而是在函数返回时产生段错误。

想要写出Bug-free的程序是非常不容易的,即使scanf读入字符串这么一个简单的函数调用都会隐藏着各种各样的错误,有些错误现象是我们暂时没法解释的:

  • 为什么变量i的存储单元紧跟在input数组后面?
  • 为什么同样是访问越界,有时出段错误有时不出段错误?
  • 为什么访问越界的段错误在函数返回时才出现?
  • 还有最基本的问题,为什么scanf输入整型变量就必须要加&,否则就出段错误,而输入字符串就不要加&?

这些问题在后续章节中都会解释清楚。

其实现在讲scanf这个函数为时过早,读者还不具备充足的基础知识。

学C语言不可能不去了解底层计算机体系结构和操作系统的原理,不了解底层原理连一个scanf函数都没办法用好,更没有办法保证写出正确的程序。

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
目录
相关文章
|
3月前
|
NoSQL Linux C语言
Linux GDB 调试
Linux GDB 调试
65 10
|
3月前
|
NoSQL Linux C语言
嵌入式GDB调试Linux C程序或交叉编译(开发板)
【8月更文挑战第24天】本文档介绍了如何在嵌入式环境下使用GDB调试Linux C程序及进行交叉编译。调试步骤包括:编译程序时加入`-g`选项以生成调试信息;启动GDB并加载程序;设置断点;运行程序至断点;单步执行代码;查看变量值;继续执行或退出GDB。对于交叉编译,需安装对应架构的交叉编译工具链,配置编译环境,使用工具链编译程序,并将程序传输到开发板进行调试。过程中可能遇到工具链不匹配等问题,需针对性解决。
102 3
|
3月前
|
NoSQL
技术分享:如何使用GDB调试不带调试信息的可执行程序
【8月更文挑战第27天】在软件开发和调试过程中,我们有时会遇到需要调试没有调试信息的可执行程序的情况。这可能是由于程序在编译时没有加入调试信息,或者调试信息被剥离了。然而,即使面对这样的挑战,GDB(GNU Debugger)仍然提供了一些方法和技术来帮助我们进行调试。以下将详细介绍如何使用GDB调试不带调试信息的可执行程序。
107 0
|
5月前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
45 1
|
5月前
|
NoSQL Linux C语言
Linux gdb调试的时候没有对应的c调试信息库怎么办?
Linux gdb调试的时候没有对应的c调试信息库怎么办?
32 0
|
5月前
|
NoSQL Linux C++
Linux C/C++ gdb调试正在运行的程序
Linux C/C++ gdb调试正在运行的程序
|
5月前
|
NoSQL Linux C++
Linux C/C++ gdb调试core文件
Linux C/C++ gdb调试core文件
|
5月前
|
NoSQL Linux C++
Linux C/C++ gdb调试
Linux C/C++ gdb调试
|
6月前
|
NoSQL Ubuntu 测试技术
【GDB自定义指令】core analyzer结合gdb的调试及自定义gdb指令详情
【GDB自定义指令】core analyzer结合gdb的调试及自定义gdb指令详情
96 1
|
6月前
|
NoSQL 编译器 C语言
【GDB调试技巧】提高gdb的调试效率
【GDB调试技巧】提高gdb的调试效率
82 1
下一篇
无影云桌面