段错误产生原因及简单的调试方法(解决树莓派编译没问题,运行时出现Segmentation fault)

15 篇文章 1 订阅
15 篇文章 0 订阅

段错误产生原因

1.访问不存在的内存地址

如下面代码,ptr没有申请空间就直接拷贝数据:

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

int main(int argc, char *argv[])
{
   char *ptr = NULL;
   //This is the wrong implementation:
   strncpy(ptr, "abc", 3);//ptr没有申请空间就直接使用

   //The right way:
   //ptr = (char *)malloc(sizeof(char) * 10);
   //memset(ptr, 0, 10);
   //strncpy(ptr, "abc", 3);

   return 0;
}

2.访问只读的内存地址

错误做法:往字符串常量空间拷贝新的数据

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

int main(int argc, char *argv[])
{
    char *ptr = "test";
    strcpy(ptr, "TEST1");

    return 0;
}

3.访问系统保护的内存地址

如:

#include <stdio.h>

int main(int argc, char *argv[])
{
    int *ptr = (int *)0;
    *ptr = 100;

    return 0;
}

4.栈溢出

如:

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

int main(int argc, char *argv[])
{
    main(argc, argv);
}

初学时两种常用的段错误调试方法

1.使用printf输出调试信息

这个是看似最简单但往往很多情况下是十分有效的调试方式,也许可以说是程序员用的最多的调试方式。简单来说,就是在程序的重要代码附近加上printf输出信息,这样可以跟踪并打印出段错误在代码中最可能出现的位置。
使用案例:
以下面这段错误代码为例:

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

int main(int argc, char *argv[])
{
   char *ptr = NULL;
   //This is the wrong implementation:
   strncpy(ptr, "abc", 3);//ptr没有申请空间就直接使用

   return 0;
}

可以在代码中添加printf调试信息:

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

int main(int argc, char *argv[])
{
    printf("line:%d\n", __LINE__); //单纯打印代码行数
   char *ptr = NULL;
   //This is the wrong implementation:
   printf("line:%d\n", __LINE__); //单纯打印代码行数
   strncpy(ptr, "abc", 3);//ptr没有申请空间就直接使用
    printf("line:%d\n", __LINE__); //单纯打印代码行数

   return 0;
}

编译运行后,会有如下输出:

line:7
line:10
Segmentation fault (core dumped)

通过日志信息,就可以看到strncpy(ptr, “abc”, 3);语句没有被执行,我们就可以根据定位到的位置来排除ptr是否是未分配空间或者分配的空间不足引发的问题

2.使用gcc和gdb

调试步骤:
1、为了能够使用gdb调试程序,在编译阶段加上-g参数,还是以下面这段错误代码为例:

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

int main(int argc, char *argv[])
{
   char *ptr = NULL;
   //This is the wrong implementation:
   strncpy(ptr, "abc", 3);//ptr没有申请空间就直接使用

   return 0;
}

编译代码添加-g选项

gcc -g -o test test.c

编译出test程序,然后用gdb调试:

linux@linux:~/test$ gdb ./test
GNU gdb (Ubuntu 8.1-0ubuntu3) 8.1.0.20180409-git
Copyright (C) 2018 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 "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./test...done.
(gdb) r
Starting program: /home/linux/test/test 

Program received signal SIGSEGV, Segmentation fault.
0x0000555555554611 in main (argc=1, argv=0x7fffffffe528) at test.c:9
9                               strncpy(ptr, "abc", 3);//ptr没有申请空间就直接使用
(gdb) quit
A debugging session is active.

        Inferior 1 [process 15829] will be killed.

Quit anyway? (y or n) y

从输出看出,程序到SIGSEGV信号,触发段错误,并提示地址0x0000555555554611以及代码第9行出错。

当然,还有利用core文件和gdb配置配合调试、使用objdump以及catchsegv命令的其他更为复杂的调试手段,这里就不展开讲。

  • 5
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

从入门到捕蛇者说

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值