数组越界是一颗隐形炸弹 数组越界会导致内存泄漏吗
yuyutoo 2024-10-24 17:50 6 浏览 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
相关推荐
- Mysql和Oracle实现序列自增(oracle创建序列的sql)
-
Mysql和Oracle实现序列自增/*ORACLE设置自增序列oracle本身不支持如mysql的AUTO_INCREMENT自增方式,我们可以用序列加触发器的形式实现,假如有一个表T_WORKM...
- 关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)
-
概述今天主要简单介绍一下Oracle12c的一些新特性,仅供参考。参考:http://docs.oracle.com/database/121/NEWFT/chapter12102.htm#NEWFT...
- MySQL CREATE TABLE 简单设计模板交流
-
推荐用MySQL8.0(2018/4/19发布,开发者说同比5.7快2倍)或同类型以上版本....
- mysql学习9:创建数据库(mysql5.5创建数据库)
-
前言:我也是在学习过程中,不对的地方请谅解showdatabases;#查看数据库表createdatabasename...
- MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别
-
执行"CREATETABLE新表ASSELECT*FROM原表;"后,新表与原表的字段一致,但主键、索引不会复制到新表,会把原表的表记录复制到新表。...
- Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出
-
在街上看到的PandaDunk的超载可能让一些球鞋迷们望而却步,但Dunk的浪潮仍然强劲,看不到尽头。我们看到的很多版本都是为女性和儿童制作的,这种新配色为后者引入了一种令人耳目一新的新选择,而...
- 美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍
-
多功能雷达AN/SPY-1的特性和技术能力,该雷达已经在美国海军服役了30多年,其修改-AN/SPY-1A、AN/SPY-1B(V)、AN/SPY-1D、AN/SPY-1D(V),以及雷神...
- 汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)
-
全面分析汽车音响使用或安装技术常识一:主机是大多数人最熟习的音响器材,有关主机的各种性能及规格,也是耳熟能详的事,以下是一些在使用或安装时,比较需要注意的事项:LOUDNESS:几年前的主机,此按...
- 【推荐】ProAc Response系列扬声器逐个看
-
有考牌(公认好声音)扬声器之称ProAcTablette小音箱,相信不少音响发烧友都曾经,或者现在依然持有,正当大家逐渐掌握Tablette的摆位设定与器材配搭之后,下一步就会考虑升级至表现更全...
- #本站首晒# 漂洋过海来看你 — BLACK&DECKER 百得 BDH2000L无绳吸尘器 开箱
-
作者:初吻给了烟sco混迹张大妈时日不短了,手没少剁。家里有了汪星人,吸尘器使用频率相当高,偶尔零星打扫用卧式的实在麻烦(汪星人:你这分明是找借口,我掉毛是满屋子都有,铲屎君都是用卧式满屋子吸的,你...
- 专题|一个品牌一件产品(英国篇)之Quested(罗杰之声)
-
Quested(罗杰之声)代表产品:Q212FS品牌介绍Quested(罗杰之声)是录音监听领域的传奇品牌,由英国录音师RogerQuested于1985年创立。在成立Quested之前,Roger...
- 常用半导体中英对照表(建议收藏)(半导体英文术语)
-
作为一个源自国外的技术,半导体产业涉及许多英文术语。加之从业者很多都有海外经历或习惯于用英文表达相关技术和工艺节点,这就导致许多英文术语翻译成中文后,仍有不少人照应不上或不知如何翻译。为此,我们整理了...
- Fyne Audio F502SP 2.5音路低音反射式落地音箱评测
-
FyneAudio的F500系列,有新成员了!不过,新成员不是新的款式,却是根据原有款式提出特别版。特别版产品在原有型号后标注了SP字样,意思是SpecialProduction。Fyne一共推出...
- 有哪些免费的内存数据库(In-Memory Database)
-
以下是一些常见的免费的内存数据库:1.Redis:Redis是一个开源的内存数据库,它支持多种数据结构,如字符串、哈希表、列表、集合和有序集合。Redis提供了快速的读写操作,并且支持持久化数据到磁...
- RazorSQL Mac版(SQL数据库查询工具)
-
RazorSQLMac特别版是一款看似简单实则功能非常出色的SQL数据库查询、编辑、浏览和管理工具。RazorSQLformac特别版可以帮你管理多个数据库,支持主流的30多种数据库,包括Ca...
你 发表评论:
欢迎- 一周热门
-
-
前端面试:iframe 的优缺点? iframe有那些缺点
-
带斜线的表头制作好了,如何填充内容?这几种方法你更喜欢哪个?
-
漫学笔记之PHP.ini常用的配置信息
-
其实模版网站在开发工作中很重要,推荐几个参考站给大家
-
推荐7个模板代码和其他游戏源码下载的网址
-
[干货] JAVA - JVM - 2 内存两分 [干货]+java+-+jvm+-+2+内存两分吗
-
正在学习使用python搭建自动化测试框架?这个系统包你可能会用到
-
织梦(Dedecms)建站教程 织梦建站详细步骤
-
【开源分享】2024PHP在线客服系统源码(搭建教程+终身使用)
-
2024PHP在线客服系统源码+完全开源 带详细搭建教程
-
- 最近发表
-
- Mysql和Oracle实现序列自增(oracle创建序列的sql)
- 关于Oracle数据库12c 新特性总结(oracle数据库19c与12c)
- MySQL CREATE TABLE 简单设计模板交流
- mysql学习9:创建数据库(mysql5.5创建数据库)
- MySQL面试题-CREATE TABLE AS 与CREATE TABLE LIKE的区别
- Nike Dunk High Volt 和 Bright Spruce 预计将于 12 月推出
- 美国多功能舰载雷达及美国海军舰载多功能雷达系统技术介绍
- 汽车音响怎么玩,安装技术知识(汽车音响怎么玩,安装技术知识视频)
- 【推荐】ProAc Response系列扬声器逐个看
- #本站首晒# 漂洋过海来看你 — BLACK&DECKER 百得 BDH2000L无绳吸尘器 开箱
- 标签列表
-
- mybatis plus (70)
- scheduledtask (71)
- css滚动条 (60)
- java学生成绩管理系统 (59)
- 结构体数组 (69)
- databasemetadata (64)
- javastatic (68)
- jsp实用教程 (53)
- fontawesome (57)
- widget开发 (57)
- vb net教程 (62)
- hibernate 教程 (63)
- case语句 (57)
- svn连接 (74)
- directoryindex (69)
- session timeout (58)
- textbox换行 (67)
- extension_dir (64)
- linearlayout (58)
- vba高级教程 (75)
- iframe用法 (58)
- sqlparameter (59)
- trim函数 (59)
- flex布局 (63)
- contextloaderlistener (56)