百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程网 > 正文

数组越界是一颗隐形炸弹 数组越界会导致内存泄漏吗

yuyutoo 2024-10-24 17:50 10 浏览 0 评论


数组越界问题大家在软件开发过程中应该都司空见惯了。如果你没见过,大概率是一个新手,工作经验不足,倒不是说你自己会生产这种 BUG,但有些同事却可能是 BUG 搬运工。

在鱼鹰五年的工作开发过程中,除了在北京刚毕业那会没遇到这种隐藏问题(碰到的都是自己生产的 BUG,不过自产自销,也还行),在深圳的这几家公司都遇到了数组越界的问题。

问题一

第一个问题是关于串口驱动导致的越界(最终结果是 hardfault),这个鱼鹰在以前的笔记中也反复强调了,因为这个问题差点导致自己熬了一个通宵,也是醉了(老代码的一个 bug)。

当然这个问题的解决和当时没有在线调试环境(当时的 PCB 板子通过串口烧录代码,没有调试接口,大坑)有很大关系,否则解决起来会快不少。

当然当时鱼鹰也没掌握这个方法《BUG 终结者,现场抓获!|颠覆认知》,否则出现问题时,这种小问题分分钟定位它。

所以当时解决这个问题,全靠玄学:运气。

否则这个问题不知道要蹂躏鱼鹰多少天。

问题二

这个问题在前东家遇到。当时的环境是 boot + app 形式。boot 代码也是跑了多年的老代码,从来没有出现过问题。

直到有一次版本升级,发现程序不能跳转到 app 正常运行(具体细节不记得了)。

当时有同事怀疑是我当时更新的 printf 打印函数有关系,因为当时的版本更新有这个改动。但鱼鹰对自己写的代码还是比较有自信的,并且我的 printf 改动和 app 跳转能有什么关系。

但怀疑到你头上了,同时鱼鹰也经常负责定位这类疑难杂症,刚好空闲,那就去瞧瞧看了,证明一下这不是你的问题。

因为问题 100% 复现,又掌握了那个现场抓获的技巧,很快就定位到是 boot 的一段代码申请的栈数组空间不足,导致被调用的函数使用这块空间时越界了。

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!

无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。

点击这里找小助理0元领取:加微信领取资料


类似下面这种:

func2(uint8_t *buff)
{
  i = 5;
  buff[i] = 0;
}
fun1()
{
   uint8_t buff[4];
   func2(buff);
}

当然实际代码肯定不可能这么简单,i 的值是变化的,不可能一眼看出。

这个问题也是导致 hardfault(退出 func2 时,破坏了返回地址)。

看到没有,有时候二分法(二分查找有问题的代码提交)查找问题也不是那么可靠,因为问题可能根本不在提交的的代码中。

而下面的问题三也证明了这一点(当然不是说二分法没用,只是不能全靠它作为你的结果判断)。

问题三

这个问题是现东家遇到的问题。

自己开发的一个新模块,当合并到主分支时,发现开机必定 hardfault,这让我百思不得其解。自己新加入的代码,都没用到数组,怎么会hardfault。

我的第一反应就是,不是我的锅。

但问题出现在我合并的过程,也只能由我定位了。还好经验丰富,一天时间+加班几个小时,总算是定位到了。

这个问题定位有几个难点:

1、使用 C++

2、使用 O2 优化,而使用 O0 的方式问题不复现了(最蛋疼)

3、使用了 map 库函数

因此在复现率很高的情况下,还是花了这么多时间。

但好在顺利解决了(这么高的复现率,定位root case只是时间问题,信心也是 100%)。

简单来说,是以前的一段代码在使用 sprintf 时(这里强烈建议用 snprintf),导致栈缓存空间越界,然后导致上一层函数的局部变量被篡改,而这个局部变量会导致 map 传入的参数有问题,最终导致了 hardfault 。

可以看到,虽然根因在一个函数中,但最终出现问题却可能在另一个函数中。

就像犯罪现场,作案现场只有一个(root case),但可能案发现场并不是作案现场。

因此解决 bug 过程其实就是警察破案,通过蛛丝马迹找到第一作案现场,如此才能正确破案。

而这种代码在工程里面有好几处.....并且在合入我的代码之前,运行良好。所以,数组越界也不一定会 hardfault,就看你破坏的是啥了。

为什么?

大家很奇怪,为毛数据越界大部分情况下会 hardfault,有时却不会产生问题。只有思考到更深层的原因,你才能在 BUG 环绕中有所成长。

这个时候,就看你的基础扎实不扎实了。

这里来个简单示意函数(优化O0)

void func2()
{
  int i = 0;
  int buff[4];
  
  buff[4] = 0; 
}
void func1()
{
  int j = 0; // 假设该局部变量使用 r4
  func2();
}

栈空间如下(因为只有 4 个字,编译器可能 buff[4] 直接使用寄存器了,但为了简单说明,这里假设 buff 都使用了栈):

从上图我们可以知道,进入 func2 函数时,先 push,离开时 pop。

局部变量 i 使用 r4 寄存器,但是栈空间 r4 保存的是 func1 使用的 j 的值

因此,当我们数组越界时(一般越界是往高地址,因为数组索引一般是自加),很容易破坏上一个函数的栈空间,在这里破坏的是 j 的值。如果 j 很重要,那么很可能会导致 hardfault 或者其它问题(能引起 hardfault 反而是好事)。

并且这里面还有重要的返回地址 lr,如果这个值被越界破坏,那么大概率都是hardfault,因为你企图跳转到一个不存在的地址执行。

数组越界是一个很危险的 BUG,能观察到现象还好,万一是默默破坏而不能很快被察觉,成为一个隐藏 BUG,那才是最危险的。

那为啥问题三增加别的代码会触发这个 BUG ,修改优化等级又会消失呢?

这和编译器有关系,有可能你的代码导致有问题的代码使用了不同的内存布局,从而越界篡改的位置变成了重要的内存,因此出现了现象,而优化等级对栈内存布局更是有很大影响。

另外本篇笔记介绍的局部缓存数组的越界,实际上还有全局数组的越界,那种问题相对简单许多,看 map 文件即可。

因此,操作数组时,一定要时时刻刻检测数组的索引的大小,以防越界。

转载自:鱼鹰谈单片机

文章来源于数组越界是一颗隐形炸弹

原文链接:https://mp.weixin.qq.com/s/dC7dQC5oaLQYvi3TYC0S-A

相关推荐

Python操作Word文档神器:python-docx库从入门到精通

Python操作Word文档神器:python-docx库从入门到精通动动小手,点击关注...

Python 函数调用从入门到精通:超详细定义解析与实战指南 附案例

一、函数基础:定义与调用的核心逻辑定义:函数是将重复或相关的代码块封装成可复用的单元,通过函数名和参数实现特定功能。它是Python模块化编程的基础,能提高代码复用性和可读性。定义语法:...

等这么长时间Python背记手册终于来了,入门到精通(视频400集)

本文毫无套路!真诚分享!前言:无论是学习任何一门语言,基础知识一定要扎实,基础功非常的重要,找一个有丰富编程经验的老师或者师兄带着你会少走很多弯路,你的进步速度也会快很多,无论我们学习的目的是什么,...

图解Python编程:从入门到精通系列教程(附全套速查表)

引言本系列教程展开讲解Python编程语言,Python是一门开源免费、通用型的脚本编程语言,它上手简单,功能强大,它也是互联网最热门的编程语言之一。Python生态丰富,库(模块)极其丰富,这使...

Python入门教程(非常详细)从零基础入门到精通,看完这一篇就够

本书是Python经典实例解析,采用基于实例的方法编写,每个实例都会解决具体的问题和难题。主要内容有:数字、字符串和元组,语句与语法,函数定义,列表、集、字典,用户输入和输出等内置数据结构,类和对象,...

Python函数全解析:从入门到精通,一文搞定!

1.为什么要用函数?函数的作用:封装代码,提高复用性,减少重复,提高可读性。...

Python中的单例模式:从入门到精通

Python中的单例模式:从入门到精通引言单例模式是一种常用的软件设计模式,它保证了一个类只有一个实例,并提供一个全局访问点。这种模式通常用于那些需要频繁创建和销毁的对象,比如日志对象、线程池、缓存等...

【Python王者归来】手把手教你,Python从入门到精通!

用800个程序实例、5万行代码手把手教你,Python从入门到精通!...

Python从零基础入门到精通:一个月就够了

如果想从零基础到入门,能够全职学习(自学),那么一个月足够了。...

Python 从入门到精通:一个月就够了

要知道,一个月是一段很长的时间。如果每天坚持用6-7小时来做一件事,你会有意想不到的收获。作为初学者,第一个月的月目标应该是这样的:熟悉基本概念(变量,条件,列表,循环,函数)练习超过30个编...

Python零基础到精通,这8个入门技巧让你少走弯路,7天速通编程!

Python学习就像玩积木,从最基础的块开始,一步步搭建出复杂的作品。我记得刚开始学Python时也是一头雾水,走了不少弯路。现在回头看,其实掌握几个核心概念,就能快速入门这门编程语言。来聊聊怎么用最...

神仙级python入门教程(非常详细),从0到精通,从看这篇开始!

python入门虽然简单,很多新手依然卡在基础安装阶段,大部分教程对一些基础内容都是一带而过,好多新手朋友,对一些基础知识常常一知半解,需要在网上查询很久。...

Python类从入门到精通,一篇就够!

一、Python类是什么?大家在生活中应该都见过汽车吧,每一辆真实存在、能在路上跑的汽车,都可以看作是一个“对象”。那这些汽车是怎么生产出来的呢?其实,在生产之前,汽车公司都会先设计一个详细的蓝图...

学习Python从入门到精通:30天足够了,这才是python基础的天花板

当年2w买的全套python教程用不着了,现在送给有缘人,不要钱,一个月教你从入门到精通1、本套视频共487集,本套视频共分4季...

30天Python 入门到精通(3天学会python)

以下是一个为期30天的Python入门到精通学习课程,专为零基础新手设计。课程从基础语法开始,逐步深入到面向对象编程、数据处理,最后实现运行简单的大语言模型(如基于HuggingFace...

取消回复欢迎 发表评论: