当前位置: 首页 > news >正文

【GDB调试】智慧中控项目的调试

一.在执行的智慧中控项目的时候,喊语音模块唤醒(小欣小欣)的时候遇到了:Segmentation fault 段错误

在这里插入图片描述

二.遇到段错误,一般是以下情况:

“Segmentation fault”(段错误)是Linux系统中常见的程序异常终止信号。它通常发生在程序试图访问一个未分配给它的内存区域或尝试以不允许的方式访问内存时。以下是一些可能导致段错误的常见原因:

  1. 空指针解引用:如果你的程序试图通过一个空指针访问数据,这将导致段错误。

  2. 数组越界:当你试图访问数组的一个不存在的位置时,例如,数组大小为10,而你试图访问第11个元素。

  3. 野指针:指向已经释放了的内存空间的指针被称为野指针,使用这样的指针可能会导致段错误。

  4. 栈溢出:当函数调用层次太深或者局部变量占用空间过大导致栈空间耗尽时,会发生栈溢出。

  5. 多线程问题:在多线程环境中,如果两个或多个线程同时访问并修改同一块内存而没有适当的同步机制,可能会导致段错误。

  6. 非法地址操作:如向只读内存写入数据等。

  7. 内存分配失败后继续使用:当malloc()calloc()等函数返回NULL值表示内存分配失败时,如果程序没有检查这个返回值而直接使用分配的内存,就会发生段错误。

  8. 结构体或对象的成员访问:当尝试访问一个未正确初始化的对象的成员时,也可能引发段错误。

解决段错误的方法包括但不限于:

  • 使用调试器(如GDB)来定位错误发生的准确位置。
  • 检查所有指针是否都被适当地初始化,并且在使用前确认它们不是NULL。
  • 检查数组边界,确保不会越界访问。
  • 对于动态内存管理,确保释放内存后不再使用该内存。
  • 在多线程应用中,确保对共享资源的操作进行了适当的同步处理。

三.我如何解决?这里使用GDB去调试

1. 首先使用GDB去运行项目

用gdb去调试一般就这个步骤:
①在gcc后面加-g编译
②在前面加gdb去执行
③遇到(gdb)的时候,按r运行,再次遇到继续按r
④后面就会看到输出的结果,和程序奔溃的地方(哪个文件,哪行代码)。
在这里插入图片描述

2. 回到项目,找到发生错误的地方

①一般段错误就是指针的问题,经常要么是使用了空指针,要么就是指针越界了。
这里发现cur_gdev也是个指针,cur_gdv指针被拿去做了一些操作(被拿去做了if判断)。
并且这里看到cur_gdev一开始赋值是NULL,那这里就应该去看看cur_gdev后续是否有被到赋值。
如果cur_gdev没有被赋到值,又被拿去做了其它其它操作,就会出现段错误,那就是使用一个指向空的指针去跟其它的数据做if判断,就会出错。
所以这里开始怀疑cur_gdev是不是没赋到值?
在这里插入图片描述
②所以这里找到cur_gdev被赋值的代码(92行),看看cur_gdev有没有被赋到值。
在cur_gdev被赋值的代码下面加上一条printf语句打印一串数字(93行)。
执行看看会不会输出这行数字。如果输出这行数字,说明程序跑到这个printf语句了,那也就说明cur_gdev被赋值的语句也跑到了,说明cur_gdev被赋到值了。
在这里插入图片描述
③用GDB执行结果如下:
没看到输出我们加的那行代码88888888888(代码93行)?
在这里插入图片描述

3.继续去调试

①在输出888888的代码,后面加"\n"换行符试试:printf(“88888888888888888888\n”);
在这里插入图片描述
②老样子使用gdb编译、执行、按r运行

在这里插入图片描述
③老样子,在发生错误的地方,唤醒语音模块(喊小欣小欣)
④结果如下,看到了我们加的那行代码88888888888(代码93行)。说明cur_gdev被赋值的语句(92行),程序是有执行到的
在这里插入图片描述

4.继续调试,在有怀疑的地方继续加printf输出语句

①那cur_gdev被赋值的语句确实是有被执行到的,那我们在点进去看看给cur_gdev赋值的函数find_gdevice_by_key()点进去看看,cur_gdev有没有可能会被赋值为NULL

cur_gdev = find_gdevice_by_key(phead_gdev,recv_msg->buffer[2]); 

②看到find_gdevice_by_key()函数里面,这段代码的意思是:
如果链表头是空就返回空NULL
否则就去遍历链表,
遍历完链表都没有找到需要return的那个p,我们就返回空NULL

发现确实有两个会返回return,那cur_gdev确实是有可能会被赋值为空NULL的。
所以我们给每个return前面加个printf输出语句(记得后面加\n)
然后继续唤醒语音模块(喊小欣小欣),
看看最后会打印出哪个printf输出语句,那就能侧面知道return的是什么给cur_gdev
在这里插入图片描述
③看到打印的是77777,那说明后面会return的是NULL空值给cur_gdev。证明了我们的猜想。
在这里插入图片描述
在这里插入图片描述

4.继续调试,在有怀疑的地方继续加printf输出语句

①回到前面,所以刚刚唤醒语音模块(喊小欣小欣)的时候,cur_gdev确实有可能被return返回一个空值NULL的,那这里却没有对cur_gdev是NULL的时候做什么处理,导致后面cur_gdev直接被拿去做if判断了,出现了段错误。
在这里插入图片描述

②那这里加个如果cur_gdevNULL的时候的处理看看,继续验证猜想:cur_gdev是不是真的NULL
在这里插入图片描述
③结果如下:
看到输出1111111111,再次证明cur_gdev确实是NULL。然后后面就被拿去做操作了,所以是空指针操作出现的段错误。
在这里插入图片描述

5. 所以按实际需要给cur_gdev做空指针处理,如果cur_gdev为NULL就怎么怎么样。

我这里是给如果cur_gdev是空指针,我就直接退出线程。
在这里插入图片描述


http://www.mrgr.cn/news/71005.html

相关文章:

  • 记录第一次安装laravel项目
  • 企业信息化-走进身份管理之搭建篇
  • 【python爬虫之 funboost 分布式函数调度框架】
  • React(五)——useContecxt/Reducer/useCallback/useRef/React.memo/useMemo
  • 谁的年龄最小(结构体专题)
  • 阿里云ElasticSearch跨集群备份恢复实践
  • 【Linux进程篇4】谈:操作系统进程调度各种基本状态(运行,挂起,阻塞等)
  • 第18篇 :深入剖析systemverilog中 randomize 静态static约束案例(四)
  • 中国人工智能影响力人物谌鹏飞行善公益演讲--《AI就是爱》
  • 如何选择适合自己需求的可编程晶振?
  • [定时器]
  • AI Agent智能数字员工解决案例
  • 关于第二台及其的 Anaconda的安装信息
  • 计算机组成原理之SISD,SIMD,MIMD,向量处理器的基本概念
  • 基于SpringBoot的“原创歌曲分享平台”的设计与实现(源码+数据库+文档+PPT)
  • 发布rust crate
  • 国际化视野下的新蓝海:如何参与海外短剧项目?
  • C语言结构体数组
  • 灾难恢复和业务连续性:制定有效的灾难恢复计划
  • Docker入门系列——Docker-Compose
  • 抓住鸿蒙生态崛起的机遇:开发者如何应对挑战,创造更好的应用体验
  • 怎么看真假国企啊?怎么识别假冒国企的千层套路?
  • string------1
  • 通过EtherNetIP转Profinet网关实现跨品牌EthernetIP协议的PLC通讯
  • 模型再训练软件环境部署说明
  • Python100道面试题(2024持续更新中............)