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

    文章

    2484

    浏览量

    46530
  • 编程
    +关注

    关注

    88

    文章

    3440

    浏览量

    92389
  • 程序
    +关注

    关注

    114

    文章

    3631

    浏览量

    79541
  • 变量
    +关注

    关注

    0

    文章

    595

    浏览量

    28112

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

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

收藏 人收藏

    评论

    相关推荐

    windows多线程编程碰到问题,请编程高手分析

    windows多线程编程碰到问题,请编程高手分析?在VC多线程编程中有数据保护问题,如
    发表于 03-11 17:40

    数据波形数据异常分析

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

    系统变更(增加新的状态迁移条件),导致在某些状态时技术器出现异常,求可能的原因?

    系统变更(增加新的状态迁移条件),导致在某些状态时技术器出现异常,求可能的原因?
    发表于 08-23 21:31

    Java的常用异常处理方法 java推荐

    放在异常可能发生的地方,具体用法如下:try{// 程序代码}catch(ExceptionName e1){//Catch 块}catch 语句包含要捕获异常类型的声明。当保护代码块中发生
    发表于 01-19 17:26

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

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

    DSP中断处理程序导致异常

    下午好。我的处境很简单(或者应该是这样)。我有DMA从ADC消耗并行数据。当块完成时,DMA中断使用FFT库函数来计算频谱内容。这个例程本身可以正常工作。但是,当我将
    发表于 03-20 08:48

    导致STM32进入HardFault异常的原因

    1、导致异常的原因有很多,例如:直接使用未分配空间的指针、栈溢出等异常非法操作便会使程序进入“HardFault”异常状态。接下来在MDK工
    发表于 01-07 06:52

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

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

    Labview的异常崩溃

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

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

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

    如何在两程序交换变量值?

    的扇区 0 上运行。)作为参考,我使用 STM32CubeIDE 1.3.0 作为编译工具。以前用IAR的时候,程序的两变量放在noinit区的同
    发表于 02-08 08:38

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

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

    FAQ0066结构体成员未完全初始化导致程序异常的解决方法

    使用非官方程序,由于某些外设驱动在配置结构体时,未完全初始化所有成员,导致程序运行异常。以 FSMC 为例,FSMC_NORSRAMInitStructure 结构体共有 15
    发表于 10-20 06:59

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

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

    Java oom异常的原因分析

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