0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

程序中增加一个变量导致异常的分析

typedef 来源:typedef 2024-01-22 09:56 次阅读

前述

大家在平常的编程过程应该会碰到各种奇葩的问题吧,反正我最近是碰到了一次,再此跟大家分享一下。事情的原因是我在程序中增加了一个变量,然后就会导致程序每次都会进入异常。

示例代码

我将代码简化了,使用两个模块来演示这个问题。第一个模块是Dev模块。

下面是Dev模块的头文件,Dev结构体中有一个数组。

#include
#include

typedefstruct{
inta_[100];
charb_;
}Dev;

voidDevInit(Dev*c_this);

下面是Dev模块的源文件代码,里面只有一个memset。

#include"Dev.h"

voidDevInit(Dev*c_this){
memset(c_this,0,sizeof(Dev));
}

第二个模块是DevManager,相关数据结构如下:

#include"Dev.h"

#pragmapack(1)

typedefstruct{
Devuart_;
charnum_;//Addingthisvariablecausesacrash
Deviic_;
}DevManage;

#pragmapack()

DevManagedev_manage;

voidDevManagerInit(void){
DevManage*c_this=&dev_manage;

memset(c_this,0,sizeof(DevManage));

DevInit(&c_this->uart_);
DevInit(&c_this->iic_);
}

DevManage结构体包含uart以及iic设备,以及我新加入的一个num_变量,由于新增了num_变量以及与之相关的业务会导致每次调试目标板都会进入异常。

尝试解决异常问题

根据调试情况看,每次都会出现异常,说明是个小问题。就怕偶尔出现异常,不容易复现。

思路应该非常清晰,出现异常时候查看LR寄存器的值,LR寄存器主要有两个功能。

保存子程序返回地址。使用BL或BLX时,跳转指令自动把返回地址放入r14中

当异常发生时,异常模式的R14用来保存异常返回地址

根据LR寄存器的值,从而定位到是执行DevInit(&c_this->iic_)函数中的memset导致的。

第一反应是DevInit中传入的对象可能为空,操作了非法内存才导致的错误。于是又重新调试了一遍,发现DevInit中对象的地址并不为空,而且就是等于实体对象中设备的地址。

这一刻我陷入了深深的自我怀疑,memset难道不是这样用的?难道不是传入一个地址,清0,然后sizeof(DevManage)就完事了?

我这代码怎么会出错,memset就是这样用的,天王老子来我也是对的,这样的心理是不是也深度还原了碰到问题时的你们。

如果是你,该如何继续...

救命稻草

有人说,汇编是最后的救命稻草。那我也尝试抓住这根稻草,出现问题时如下图:

1b2d08ce-b8c4-11ee-8b88-92fbcf53809c.png

问题主要出现红色箭头指向的这一行,经过查询资料得知_aeabi_memclr4是一个用于ARM嵌入式系统的函数,用于将内存区域清零。函数名中的"_a"表示该函数符合ARM嵌入式应用二进制接口(Embedded Application Binary Interface,EABI)规范。在调用_aeabi_memclr4时,需要确保传入的内存地址是四字节对齐的。再看图片中的对象地址为0x200001BD,刚好比四字节对齐地址0x200001BC多了一个字节。

再回头看DevManage对象,这里使用了伪指令#pragma pack(1)让内存分配进行单字节对齐。因为Dev对象是按照四字节对齐的,紧接着引入了新的成员num_占用一个字节。所以导致iic_对象的地址相对于未增加变量之前的地址偏移了一个字节,导致不是四字节对齐的了,从而引发了错误。

就示例中的代码而言,只需要把强制DevManage对象单字节对齐的功能删除即可解决问题,因为默认情况下是四字节对齐的。

成员分配

由于#pragma pack(1)具有作用域限制,这里其实只是对num_变量做了单字节对齐的限制,而并没有对Dev对象的内存分配起到限制作用,Dev对象仍然是按照4字节对齐的(默认值),所以Dev对象的所占用的长度一定是101*4=404字节。而整个DevManager对象的大小就101 * 4 + 1 + 101 * 4 = 809字节,成员分配如下图所示。

1b37ac7a-b8c4-11ee-8b88-92fbcf53809c.png

最后

到最后在抛出一个问题,对于上述的代码在vscode中使用gcc编译执行为何没有问题?

审核编辑:汤梓红

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 模块
    +关注

    关注

    7

    文章

    2740

    浏览量

    47828
  • 编程
    +关注

    关注

    88

    文章

    3642

    浏览量

    94089
  • 程序
    +关注

    关注

    117

    文章

    3798

    浏览量

    81500
  • 变量
    +关注

    关注

    0

    文章

    613

    浏览量

    28501

原文标题:加个变量,程序崩了

文章出处:【微信号:typedef,微信公众号:typedef】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    数据波形数据异常分析

    ,试验过程,V1-的电压出现了异常点3.95V(试验进行了7、8小时后),如下图所示,左侧图为持续监控图,右侧图为正常传感器的监控图
    发表于 11-21 11:55

    分析关于STM32 芯片异常复位的经典案例!

    应用软件产生异常的地方!问题描述某STM32用户反馈,当使用STM32L4芯片的时候,程序运行段时间后,会忽然复位。复位后程序继续运行,但是还会继续复位,原因不详!问题
    发表于 04-07 08:00

    STM32局部变量过大导致栈溢出怎么去解决呢

    最近项目调试中发现只要使用memset函数对局部数组赋值时,就会导致其他全局变量值被更改,接着就进入HardFault错误。后来发现局部变量
    发表于 01-20 06:07

    Labview的异常崩溃

    起因:昨天升级程序后产线突然反馈程序异常崩溃,排查到了神奇的BUG。Labview异常崩溃报
    发表于 03-17 18:05

    请问main函数内定义的变量是在栈上吗?

    程序调试很久直数据异常,后来无意发现main函数内定义的变量定义在main以外后程序功能正
    发表于 04-01 10:12

    XDATA定义变量程序异常的原因?怎么解决?

    本人第次使用新塘N76E003单片机开发,在定义变量时DATA用完了以后,使用XDATA定义变量,发现用XDATA定义的变量程序运行时
    发表于 06-25 06:05

    实时任务处理程序设计“易变的”变量

    实时任务处理程序设计“易变的”变量
    发表于 05-15 13:52 7次下载

    变量水质参数时间异常事件检测算法

    在供水管网中部署传感器网络实时获取多个水质参数时间序列数据,当供水管网发生污染时,高效准确地检测水质异常重要问题。提出多变量水质参数时间异常
    发表于 12-07 16:17 0次下载
    多<b class='flag-5'>变量</b>水质参数时间<b class='flag-5'>异常</b>事件检测算法

    西门子PLC变量定义变量

    程序多数指令都通过变量来操作。  为指令分配变量后,即会使用指定变量的值来执行该指令。 变量
    的头像 发表于 12-23 16:25 2.1w次阅读
    西门子PLC<b class='flag-5'>变量</b>表<b class='flag-5'>中</b>定义<b class='flag-5'>变量</b>

    怎么给全局变量别名

    所谓的变量别名,就是通过通过不同的标识符,来表示同一个变量。我们知道,变量名称是给程序员使用的。在编译器的眼中,所有的
    的头像 发表于 02-14 13:38 564次阅读
    怎么给全局<b class='flag-5'>变量</b>起<b class='flag-5'>一</b><b class='flag-5'>个</b>别名

    Python异常机制(

    刻不在路上. 在今夜首先了解 什么是异常 : 软件程序在运行过程,可能会遇到能使其不能正常运行的问题,我们称之为异常,英文是:Excep
    的头像 发表于 05-11 18:17 802次阅读
    Python<b class='flag-5'>中</b>的<b class='flag-5'>异常</b>机制(<b class='flag-5'>一</b>)

    读取机器人程序变量

    其中包含引用解释器的进程指针的数据. 变量包含接下来将在解释器执行的块的数据。 根据特定的解释器,访问数据的方式如下: 读取机器人程序变量
    的头像 发表于 05-29 10:02 1120次阅读
    读取机器人<b class='flag-5'>程序</b><b class='flag-5'>中</b>的<b class='flag-5'>变量</b>

    Java oom异常的原因分析

    据,而栈内存用于存储方法调用和局部变量。 当程序需要使用更多内存时,会向操作系统请求更多的内存空间。如果操作系统无法分配足够的内存空间,就会导致OOM异常的发生。
    的头像 发表于 12-05 13:43 853次阅读

    C语言:指针内存是如何存放变量

    程序定义变量,那么在程序编译的过程,系统会
    发表于 01-08 10:14 553次阅读

    变量位置不同会死机?郭天祥老师视频的遗留问题分析答案

    在郭天祥老师视频里有问题分享,是EXMC初始化里的变量定义和初始化位置不同会导致
    的头像 发表于 02-26 09:12 422次阅读
    <b class='flag-5'>变量</b>位置不同会死机?郭天祥老师视频的遗留问题<b class='flag-5'>分析</b>答案