WhyCan Forum(哇酷开发者社区)

我们习惯了"有问题百度一下", 感谢为中文互联网持续输出优质内容的各位老铁们。 QQ: 516333132, 微信: whycan_cn (哇酷网/挖坑网/填坑网) service@whycan.cn

您尚未登录。

#1 2020-05-21 22:30:29

Quotation
会员
注册时间: 2018-10-04
累计积分: 208

F1C100s看门狗失效bug

刚调了好几个小时的灵异bug,现象是启动后有时候会死机。这时候已经启动了看门狗,但狗没有起作用,系统一直卡在那不reset。
最后调出来是个空指针错误。空指针毕竟是编程比较常见的错误,空指针能导致看门狗无效,F1C100s的这个bug也是有点严重。

一番精简之后,找到了最小复现代码:
只要用一个基类指针,指向一块内容为0的区域,调用基类的第二个虚函数,就很容易使看门狗失效并死机。

这个bug可能跟编译器的具体实现(C++类对象内存布局)有关,我用的GCC,其他编译器不一定是这样。

class Base
{
public:
    virtual void f() = 0;
    virtual void g() = 0;
};


// main():
    // 设置看门狗,5s的时长

    uint8_t empty[1024];
    memset(empty, 0, sizeof(empty));
    Base* p = (Base*)∅  // 野指针,指向了一块内容全为0的内存

    feedWatchdog();  // 喂狗
    mdelay(10);  // 等待超过1500ms则不出bug,等待0ms也不出bug,这之间都会遇到bug

    p->g();  // 调用基类的第二个虚函数(第一个没问题),从这里就死机了。看门狗无效。

离线

#2 2020-05-22 08:27:06

staunchheart
会员
注册时间: 2019-12-17
累计积分: 158

Re: F1C100s看门狗失效bug

mark一下,等待楼主继续研究。按理说野指针后看门狗应该会重置,如果真不重置是个大问题,看门狗意义何在。。
晚上我也试试。

离线

#3 2020-05-22 10:21:12

Quotation
会员
注册时间: 2018-10-04
累计积分: 208

Re: F1C100s看门狗失效bug

继续研究。C++对象内存布局虽然没有固定标准,是编译器实现的,但基本是按照《深度探索C++对象模型》的样子。
一个带有虚函数的类的指针,指向的内存区域最开头应该是类的虚函数表指针。该指针指向一个数组,数组成员是函数指针。

在上面的例子中,当调用p->g();时,由于p指向的内存区域全是0,所以被当做是地址0x0处开始为虚函数表。
g()是类的第二个虚函数,所以把地址0x4当做函数指针。
打印出地址0x0附近的内存看:

0: 0xea00000d
1: 0xe59ff014
2: 0xe59ff014
3: 0xe59ff014
4: 0xe59ff014
5: 0xe59ff014
6: 0xe59ff014
7: 0xe59ff014
8: 0x80000260

看到0x4地址处的内容是0xe59ff014,接下来会把0xe59ff014当做函数地址去调用。就是经过这个非法函数调用后,看门狗失效并且死机!
复现此bug的代码可以再精简为:

    typedef void (*FuncPtr)();
    FuncPtr f = (FuncPtr)0xe59ff014;
    f();  // 触发看门狗bug

继续做实验发现,并不是只有这一个特殊的地址调用会触发bug,实际上有很大范围的地址都能引起看门狗无效。
从 0xdba00000 ~ 0xffff4040,这个区域内的地址,如果赋值给函数指针来调用,都会引发看门狗失效bug!!小于0xdba00000或大于0xffff4040的地址调用,则能正常死机并触发看门狗。(具体地址会变化,还跟CPU频率有关,不是完全精确的范围。)
这个范围是很大的,也就是说如果程序写错了,还是会有挺大的可能性遇到此bug。

比如考虑下面这个常见的野指针访问代码,触发看门狗bug的概率并不小。

struct A
{
    int data;
    void (*func)();
};

A* a = (A*)malloc(sizeof(A));
// ...
free(a);
// a被释放,指向的地址重新分配后写入了其他内容
// ...
a->func();  // 野指针使用,危险!

离线

#4 2020-05-22 16:44:15

wupaul2001
会员
注册时间: 2019-09-30
累计积分: 157

Re: F1C100s看门狗失效bug

不用研究了,F1C100s看门狗初始化不对,你试试热重启,如果重启不了,看门狗就不正常了

离线

#5 2020-05-24 04:17:02

hoel
会员
注册时间: 2019-06-15
累计积分: 45

Re: F1C100s看门狗失效bug

Quotation 说:

刚调了好几个小时的灵异bug,现象是启动后有时候会死机。这时候已经启动了看门狗,但狗没有起作用,系统一直卡在那不reset。
最后调出来是个空指针错误。空指针毕竟是编程比较常见的错误,空指针能导致看门狗无效,F1C100s的这个bug也是有点严重。

一番精简之后,找到了最小复现代码:
只要用一个基类指针,指向一块内容为0的区域,调用基类的第二个虚函数,就很容易使看门狗失效并死机。

这个bug可能跟编译器的具体实现(C++类对象内存布局)有关,我用的GCC,其他编译器不一定是这样。

    mdelay(10);  // 等待超过1500ms则不出bug,等待0ms也不出bug,这之间都会遇到bug

嗨,你能分享你的Delay()过程吗? 我从uboot移植了地雷,只有timer0在工作并且时基错误,timer1根本不工作

最近编辑记录 hoel (2020-05-24 04:17:25)

离线

#6 2020-05-24 15:27:53

staunchheart
会员
注册时间: 2019-12-17
累计积分: 158

Re: F1C100s看门狗失效bug

Quotation 说:

继续研究。C++对象内存布局虽然没有固定标准,是编译器实现的,但基本是按照《深度探索C++对象模型》的样子。
一个带有虚函数的类的指针,指向的内存区域最开头应该是类的虚函数表指针。该指针指向一个数组,数组成员是函数指针。
....


这两天临时出去有事了,所以没能按时试。
经测试RTT用GCC编译,没有这样的问题。WDT正确的工作了。

    rt_kprintf("start wdg test----------------------------------\n");
    struct  A* a = (struct A*)malloc(sizeof(struct A));
    // ...
    free(a);
    // a被释放,指向的地址重新分配后写入了其他内容
    // ...
    a->func();  // 野指针使用,危险!
    rt_kprintf("end wdg test----------------------------------\n");


TIM图片20200524152702.png

离线

#7 2020-05-24 21:42:53

Quotation
会员
注册时间: 2018-10-04
累计积分: 208

Re: F1C100s看门狗失效bug

staunchheart 说:

这两天临时出去有事了,所以没能按时试。
经测试RTT用GCC编译,没有这样的问题。WDT正确的工作了。

    rt_kprintf("start wdg test----------------------------------\n");
    struct  A* a = (struct A*)malloc(sizeof(struct A));
    // ...
    free(a);
    // a被释放,指向的地址重新分配后写入了其他内容
    // ...
    a->func();  // 野指针使用,危险!
    rt_kprintf("end wdg test----------------------------------\n");

我那个只是示意代码。是要向那块被释放的地址里写入合适的数据,使a->func的值为0xdba00000 ~ 0xffff4040。

离线

#8 2020-05-25 10:27:25

staunchheart
会员
注册时间: 2019-12-17
累计积分: 158

Re: F1C100s看门狗失效bug

Quotation 说:

我那个只是示意代码。是要向那块被释放的地址里写入合适的数据,使a->func的值为0xdba00000 ~ 0xffff4040。

明白了,重现了,确实会这样。如果执行0xdba00000 ~ 0xffff4040确实会死,并且看门狗都会不起作用。。。
老大厉害,要如何避免呢?

离线

#9 2020-05-25 12:08:25

myxiaonia
会员
注册时间: 2019-06-18
累计积分: 37

Re: F1C100s看门狗失效bug

staunchheart 说:

明白了,重现了,确实会这样。如果执行0xdba00000 ~ 0xffff4040确实会死,并且看门狗都会不起作用。。。
老大厉害,要如何避免呢?


用mmu,比如映射到一个死循环上,然后让死在那里,就能触发wdt

离线

#10 2020-05-25 13:41:39

staunchheart
会员
注册时间: 2019-12-17
累计积分: 158

Re: F1C100s看门狗失效bug

myxiaonia 说:

用mmu,比如映射到一个死循环上,然后让死在那里,就能触发wdt

哪个早就处理好了,现在是说这样会死,并且不会触发WDT。

离线

#11 2020-05-25 22:51:49

Quotation
会员
注册时间: 2018-10-04
累计积分: 208

Re: F1C100s看门狗失效bug

我也还不知如何解决。

离线

#12 2020-05-26 11:22:26

myxiaonia
会员
注册时间: 2019-06-18
累计积分: 37

Re: F1C100s看门狗失效bug

staunchheart 说:

哪个早就处理好了,现在是说这样会死,并且不会触发WDT。

你确定已经映射到了合适的地址,我看大多数的裸机arm9大多数将虚地址和物理地址是完全一致映射的

只需要将会导致bug的虚地址,映射到一个真实的ram地址,就能捕捉到这段地址跑飞

离线

#13 2020-05-26 13:34:26

staunchheart
会员
注册时间: 2019-12-17
累计积分: 158

Re: F1C100s看门狗失效bug

myxiaonia 说:

你确定已经映射到了合适的地址,我看大多数的裸机arm9大多数将虚地址和物理地址是完全一致映射的

只需要将会导致bug的虚地址,映射到一个真实的ram地址,就能捕捉到这段地址跑飞

兄弟可能没有仔细看我们讨论的是什么问题,我们现在讨论的时当不小心野指针时,正好指向这一地址,系统会死。
正常情况下死了的时候看门狗会将设备重启,但这种情况下看门狗不起作用,只能人工去重启。
而不是在讨论为什么要指向这个地址。。。

离线

#14 2020-05-27 09:06:26

myxiaonia
会员
注册时间: 2019-06-18
累计积分: 37

Re: F1C100s看门狗失效bug

staunchheart 说:

兄弟可能没有仔细看我们讨论的是什么问题,我们现在讨论的时当不小心野指针时,正好指向这一地址,系统会死。
正常情况下死了的时候看门狗会将设备重启,但这种情况下看门狗不起作用,只能人工去重启。
而不是在讨论为什么要指向这个地址。。。

0xdba00000 ~ 0xffff4040,将这个虚地址段用mmu映射到sdram区,这个总可以完成的吧!这样cpu不会司机了,因为实地址是真实可用地址啊

离线

页脚

工信部备案:粤ICP备20025096号-1 Powered by FluxBB