搜索
bottom↓
回复: 43

两天时间解决了一个BUG,函数再入引起,不要忽视警告信息

[复制链接]

出10入120汤圆

发表于 2019-12-1 20:26:23 | 显示全部楼层 |阅读模式
本帖最后由 makesoft 于 2019-12-1 20:58 编辑

没想到51的小程序调试起来这么麻烦,花了整整两天时间,让俺这老江湖汗颜。

其实就是偷懒造成的,一个函数在程序初始化时使用,这个时候系统任何中断并没有打开,另外这个函数在定时中断中也有使用,天真的认为不存在同时调用的可能,所以不可能存在再入的问题,就是没理会重复调用的告警信息。

后来程序不定时的出现问题,因为开始已经有了不可能同时调用再入这个函数的场合,所以就没有检查这个问题。

实在没有办法,刚才检查MAP信息,TNND才发现,其实不仅仅有再入的问题,这个函数使用的局域变量占用的地址,有一个是和其他函数是重复覆盖使用的,真相大白了,两天时间就是不想写一个reentrant,因为会增加一点点代码。

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入8汤圆

发表于 2019-12-1 20:52:14 | 显示全部楼层
函数同时被调用了?局部变量被赋值,不是期望的值

出0入442汤圆

发表于 2019-12-1 22:02:58 来自手机 | 显示全部楼层
lz,c代码函数里面的变量都在栈里面,不可能出现地址重复的

出0入8汤圆

发表于 2019-12-1 22:52:00 来自手机 | 显示全部楼层
函数局部变量是定义在栈里面的,肯定会和其他函数的局部变量重合。我说的没错吧?

出10入120汤圆

 楼主| 发表于 2019-12-1 22:59:10 来自手机 | 显示全部楼层
wye11083 发表于 2019-12-1 22:02
lz,c代码函数里面的变量都在栈里面,不可能出现地址重复的

keil c51优化的时候会判断函数会不会嵌套调用,不存在这种关系的话存在局域变量复用的问题。
并不是所有编译器局域变量都是栈操作的。

出0入0汤圆

发表于 2019-12-1 23:40:38 | 显示全部楼层
一个函数在程序初始化时使用,这个时候系统任何中断并没有打开

初始化后,函数已经执行完退出,不会影响第一次中断调用的

倒是怀疑定时中断时间间隔过小,造成前次中断未返回,后次中断又来了,没做再入函数设置,当然会出问题

出10入120汤圆

 楼主| 发表于 2019-12-1 23:47:25 来自手机 | 显示全部楼层
johnlj 发表于 2019-12-1 23:40
一个函数在程序初始化时使用,这个时候系统任何中断并没有打开

初始化后,函数已经执行完退出,不会影响第 ...

哈哈,就是一样的思维才导致查了两天才解决问题。
当中断和主程序共同可以调用一个函数的时候,这个函数不是再入属性,编译器优化这个函数局域变量占用内存的时候,可能和主程序其他函数做覆盖优化,这个时候问题就发生了,哪怕仅仅覆盖一个字节。
当局域变量不是静态分配而是堆栈的话,就没有这个问题发生了。

出0入442汤圆

发表于 2019-12-1 23:55:31 来自手机 | 显示全部楼层
makesoft 发表于 2019-12-1 23:47
哈哈,就是一样的思维才导致查了两天才解决问题。
当中断和主程序共同可以调用一个函数的时候,这个函数 ...

我ca,我想到之前用avr8时,gcc编译的代码在超过8kb之后会产生各种莫名其妙的问题,死机,执行异常,中断异常,等等。。。貌似是同一类问题。汇编都查了,始终无解,最后放弃avr了

出0入0汤圆

发表于 2019-12-1 23:59:48 | 显示全部楼层
makesoft 发表于 2019-12-1 23:47
哈哈,就是一样的思维才导致查了两天才解决问题。
当中断和主程序共同可以调用一个函数的时候,这个函数 ...

看明白是,是初始化调用该函数后,其占用的临时变量空间的某个字节被其它函数使用,然后中断中该函数继续使用原来的临时变量空间,就出现了bug

那么减低编译优化级别,会不会避开这个问题?

出10入120汤圆

 楼主| 发表于 2019-12-2 06:26:07 来自手机 | 显示全部楼层
默认优化8级,并且64K程序空间现在只剩余几百字节,不然也不吝啬使用reentrant啊

出0入93汤圆

发表于 2019-12-2 06:56:28 | 显示全部楼层
makesoft 发表于 2019-12-2 06:26
默认优化8级,并且64K程序空间现在只剩余几百字节,不然也不吝啬使用reentrant啊 ...

搞成11级优化,全局寄存器着色,您试下,估计能剩余2kB代码空间出来

出0入0汤圆

发表于 2019-12-2 07:27:49 来自手机 | 显示全部楼层
不知道不开优化会是什么情况

出0入0汤圆

发表于 2019-12-2 08:06:03 | 显示全部楼层
这个只能养成习惯
中断中尽量避免调用子函数,实在需要,就写成专门给这个中断用的,不同的中断之间也是要这样隔离
复杂的主逻辑,全部放在主程序里,调用复杂层次的子函数结构

出1325入193汤圆

发表于 2019-12-2 08:11:47 | 显示全部楼层
中断中尽量避免调用子函数,实在需要,就写成专门给这个中断用的,不同的中断之间也是要这样隔离    最实用 接地气的建议

出0入0汤圆

发表于 2019-12-2 08:13:23 来自手机 | 显示全部楼层
楼主,请问当函数内部局域变量不是静态分配而是堆栈的话,就没有这个问题吗?

出0入0汤圆

发表于 2019-12-2 08:13:34 | 显示全部楼层
我之前也犯过和你一样的错误,搞两天没搞明白,后来还是求助后发现的问题。

和你一样,同一个函数中断和应用程序都有调用,我是中断指定了寄存器组,而调用函数却没指定,然后keil没有任何报警,就这么被坑了两天

出0入0汤圆

发表于 2019-12-2 08:14:18 | 显示全部楼层
823032003 发表于 2019-12-2 08:13
楼主,请问当函数内部局域变量不是静态分配而是堆栈的话,就没有这个问题吗? ...

是的  加重入后会使用栈

出100入113汤圆

发表于 2019-12-2 08:56:09 | 显示全部楼层
上次在一个帖子里提到函数可重入性的问题,被人嗤之以鼻,觉得自己没有这些概念,同样写了好多程序。最怕根本没有这个概念的人,还觉得自己写的程序很“完美”。

出100入113汤圆

发表于 2019-12-2 08:57:24 | 显示全部楼层
本帖最后由 saccapanna 于 2019-12-2 09:02 编辑
wye11083 发表于 2019-12-1 22:02
lz,c代码函数里面的变量都在栈里面,不可能出现地址重复的


你说的这种函数,叫做纯函数,纯函数都是可以重入的。但是使用了全局变量等的函数(内部变量使用 static 修饰也是一样的),就不可重入了,或者要做保护。

出0入0汤圆

发表于 2019-12-2 09:02:55 来自手机 | 显示全部楼层
只有51才会有这个问题,keil c在连接时才分配局部变量的内存,它会分析函数调用关系来确定每个函数里各个局部变量的地址,这都是51硬件维护的栈空间只有256字节缘故。其他处理器一般都会吧局部变量在栈里面分配。

出0入0汤圆

发表于 2019-12-2 09:17:12 | 显示全部楼层
keil c51默认的8级优化,我在读写矩阵键盘时,总是固定的一个按键没反应,其他按键都没问题;换成按键程序一模一样,主程序不太一样的另一个板子上,还是按键有问题,但是换了个按键固定没反应。后来这两套程序都把优化等级改成0,就没有这个问题了,到现在都不知道啥原因。

出0入0汤圆

发表于 2019-12-2 09:19:48 | 显示全部楼层
中断里不放函数就好啦, 要放就用全局变量或静态变量

出0入0汤圆

发表于 2019-12-2 09:23:19 | 显示全部楼层
0 warning, 0 error.

出0入8汤圆

发表于 2019-12-2 09:27:54 | 显示全部楼层
takashiki 发表于 2019-12-2 06:56
搞成11级优化,全局寄存器着色,您试下,估计能剩余2kB代码空间出来

请教一下,11 级优化,我怎么看到只有 9 级呢,在哪里设置?

出0入4汤圆

发表于 2019-12-2 09:57:19 | 显示全部楼层
你这个还好解决,上次用renesas的EEPROM Flash库,直接覆盖变量值,那找起来才痛苦。。。
因为那个库是不开源的,后来还是根据网上的提示,猜出是这个问题,重新定义了dr文件才搞定。

出870入263汤圆

发表于 2019-12-2 10:01:35 | 显示全部楼层
wye11083 发表于 2019-12-1 22:02
lz,c代码函数里面的变量都在栈里面,不可能出现地址重复的


你错了,pic的c编译器你去试试。
而且,51的c编译器也有这种模式

出870入263汤圆

发表于 2019-12-2 10:05:22 | 显示全部楼层
本帖最后由 armstrong 于 2019-12-2 10:08 编辑

我用过pic,51的c编译器,这两个编译器都有一种没有栈的编译模式,函数的局部变量其实都是全局变量复用。
特别是pic8,根本没有别的选择!51还有得选,pic8在硬件上就没有栈。
所以用了arm之后,再也不想用pic和51了,这些芯片是半残废。
就是最简陋的cortex-m0,也是完整的c语言支持,完整的32为平面寻址。

出0入8汤圆

发表于 2019-12-2 10:13:20 | 显示全部楼层
armstrong 发表于 2019-12-2 10:05
我用过pic,51的c编译器,这两个编译器都有一种没有栈的编译模式,函数的局部变量其实都是全局变量复用。
...

我也不想用的,可是谁叫它便宜

出0入0汤圆

发表于 2019-12-2 10:21:47 | 显示全部楼层
多谢分享,标记一下

出0入475汤圆

发表于 2019-12-2 10:22:42 来自手机 | 显示全部楼层
看到后一震,难道之前的串口也有这样的问题?初始化后没有到主循环之前调用了一下打印,然后开启定时器,后面定时器中会打印,当然编译也是同样的警告,莫非这样也存在隐患?想想害怕,不过从实际情况来看,这么多年了也没有哪里有问题,估计和优化有关吧?不优化应该可能没问题

出0入93汤圆

发表于 2019-12-2 10:30:31 | 显示全部楼层
security 发表于 2019-12-2 09:27
请教一下,11 级优化,我怎么看到只有 9 级呢,在哪里设置?

首先要在Device选项卡中设置使用LX51代替BL51,此时C51选项卡才会出现优化等级10和11,并且尽量使用AJMP/ACALL而不是LJMP/LCALL。

此时多出两个优化等级,而且尽可能少用LJMP/LCALL的选项由灰色变为可用。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入8汤圆

发表于 2019-12-2 10:53:41 | 显示全部楼层
takashiki 发表于 2019-12-2 10:30
首先要在Device选项卡中设置使用LX51代替BL51,此时C51选项卡才会出现优化等级10和11,并且尽量使用AJMP/ ...


可以了,多谢赐教。
弄到 11 级,果然省了 1.8 K 的空间,不敢相信,就是不知道程序还能不能正常跑。

出10入120汤圆

 楼主| 发表于 2019-12-2 10:56:30 | 显示全部楼层
saccapanna 发表于 2019-12-2 08:56
上次在一个帖子里提到函数可重入性的问题,被人嗤之以鼻,觉得自己没有这些概念,同样写了好多程序。最怕根 ...

正常的,很多人估计最大代码长度也就是几K,大程序和小程序策略是不同的,这些东西不会注重的。

出0入0汤圆

发表于 2019-12-16 14:34:07 | 显示全部楼层
涨知识了

出0入22汤圆

发表于 2019-12-16 14:50:55 | 显示全部楼层
printf是不是可重入的呢?我到处都在用printf,看各位的描述,担心ing

出0入0汤圆

发表于 2019-12-16 22:06:18 | 显示全部楼层
zxq6 发表于 2019-12-16 14:50
printf是不是可重入的呢?我到处都在用printf,看各位的描述,担心ing

我上网查了,是不可重入的,涉及IO的都是

出0入0汤圆

发表于 2019-12-17 04:32:57 | 显示全部楼层
>gcc编译的代码在超过8kb之后会产生各种莫名其妙的问题,死机,执行异常,中断异常,等等。。。貌似是同一类问题。汇编都查了,始终无解,最后放弃avr了
What is the size of the AVR (<=8K Bytes)?

出0入0汤圆

发表于 2019-12-17 23:22:39 | 显示全部楼层
刚参加工作那会,遇到过函数重入问题
还好当时老大经验丰富,很快指出问题所在了,感谢曾经的老大

出0入0汤圆

发表于 2019-12-18 00:48:10 来自手机 | 显示全部楼层
还是技术贴看着有意思_

出0入0汤圆

发表于 2019-12-18 09:01:35 | 显示全部楼层
记得开始写程序的时候,写中断都是非常小心的,函数是一定不会在中断产生的,代码的长度都严格控制,能在主循环中写的一定不放入中断中。

慢慢的,现在也开始偷懒了,中断中也不时出现函数了,看来是警觉性落后了呀!!

出10入120汤圆

 楼主| 发表于 2019-12-18 09:08:04 | 显示全部楼层
leicai05 发表于 2019-12-18 09:01
记得开始写程序的时候,写中断都是非常小心的,函数是一定不会在中断产生的,代码的长度都严格控制,能在主 ...

其实我从来都不同意函数不放中断的这种说法,整个CPU运行时间计算好了,各种中断优先级事先规划好了,中断里的函数运行时间是可预测的,这样的程序是没有任何问题的。

天天说中断里面不放函数的,我搞不清楚程序代码量有多少,1000行还是10000行还是十万行?这几种情况当然做法也是完全异同的,大程序有大程序的构架,小程序有小程序的做法,不能一概而论。

出0入0汤圆

发表于 2019-12-18 09:27:44 | 显示全部楼层
makesoft 发表于 2019-12-18 09:08
其实我从来都不同意函数不放中断的这种说法,整个CPU运行时间计算好了,各种中断优先级事先规划好了,中 ...

哎,不知道你有没有体会过,小众行业,项目驱动的研发,老板和客户的需求总是随心所欲,有时候更是变态的;

“这个项目就是要快,慢了就黄了,你不知道竞争有多么激烈,要快,马上要发货......
这个中断处理信号10us后要跟随xx信号动作, 持续时间需要多100us。如果xx信号检测到了动作,又要xxxx.........”

无数个这样的需求,能有具体的要求还是不错的,就怕那种,老板和客户都只是要这个结果,具体怎么实现也不清楚,对于某些指标就是要反应快,
不得不在中断中完成。而且还可能跟持续时间扯上关系,还有就是好几个中断信号,相互交叉。发货就是要快!!!!

这种情况下,写出来捉急的代码可能性是很高的!!
老板的逻辑是,先拿出货物出去交给客户再说,就算以后有bug,生意至少还由得做;拿不出东西,生意就黄了。

出10入120汤圆

 楼主| 发表于 2019-12-18 09:34:05 | 显示全部楼层
leicai05 发表于 2019-12-18 09:27
哎,不知道你有没有体会过,小众行业,项目驱动的研发,老板和客户的需求总是随心所欲,有时候更是变态的 ...

确实是这样,相互理解吧,其实大家都有大家的苦衷。

我也讨厌程序修修改改,大修下来几次自己都不认识这程序是自己写的了

出0入0汤圆

发表于 2019-12-18 16:45:01 来自手机 | 显示全部楼层
不放过任何一条警告的默默飘过。
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-24 06:18

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表