程序小白
认证:优质创作者
作者动态
小小调度器——开局default,优雅总藏于细节之中
04-02 09:23
小小调度器——调度器核心的纯C实现
04-01 14:09
小小调度器——原来C代码还能这么写,原作者没少挨打吧!
03-27 15:42
解析由系统库引发的hardfault血案(RT-Thread+ESP32)
2023-07-17 16:04
TINA瞬时现象仿真分析——运放缓冲器振铃
2023-02-28 11:38

解析由系统库引发的hardfault血案(RT-Thread+ESP32)

      最近使用RTthread用于驱动esp32联网过程中遇到了一个严重bug,刚开始并不晓得问题是出自哪里,烦恼三千丝。(唉,并不是系统提供的库就没有问题,一不小心在收集bug完善库的路上渐行渐远。。。)

先看下finsh后台给出的错误提示信息:


一、hard fault初步分析:


      首先一点,这是个hard fault故障,也就是线程飞走了(可能出现的错误:指针出错or内存溢出),出现的线程是clktask(这是一个灰常的重要的提示,帮你锁定执行过程中出错的线程)。

      上面还有一条提示执行AT+CIPDOMIAN=XXX网站错误,这条AT指令提示很重要,含义是域名解析失败。

       最大的难题,上面的故障并不是每次都出现,这就给解决问题带来了很大的困扰。因为大部分时间都是连接网络都是正常的,那么该怎样复现这个故障才是最重要的,只有每次都能模拟出该故障,才能进一步分析。


二、hard fault模拟再现:


有一个点要注意就是,每次发生hard fault 都会伴随有执行AT+CIPDOMIAN=XXX失败,也就是域名解析失败,如何模拟域名解析失败,首先你要了解一个点,esp32的域名解析服务ip就是其自身,也就是dns的ip应该与esp32的ip是重合的,这一点验证也很简单,通过执行ipconfig看看打印信息就可以确定。

接下来就是要模拟AT+CIPDOMAIN=XXX失败的情况,可以将ESP32连接路由器网络断开,这样相当于ESP32处于局域网的状态,这个时候执行AT+CIPDOMAIN=XXX就是failed状态,再执行完成后,返回的就是失败状态,实际模拟过程中也出现了,能确认百分百模拟出hard fault以后,就要进入调试阶段了。


三、hard fault调试阶段:


      进入全仿真,通过断点调试,大概锁定clktask线程中,发生hard fault的函数,通过单步调试发现,最终执行函数路径为:rt_tcpclient_start——》socket_init——》Gethostbyname;

      真正导致hard fault的位置是socket_init函数中:dst_addr.sin_addr = *((struct in_addr *)hostname->h_addr);

因为通过 hostname = gethostbyname(url);返回的hostname为NULL,所以对空指针进行操作,直接导致hard fault。


四、基于hostname为NULL,进行程序改进:


基于以上的问题点,对tcpclient.c文件进行了局部改进后,完美解决hard fault问题,改进如下:

基于rtthread进行软件开发过程中,会遇到很多奇怪的问题,遇到相同问题的概率太低了,更多具有参考的是分析思路,而非题目本身。分享快乐。

声明:本内容为作者独立观点,不代表电子星球立场。未经允许不得转载。授权事宜与稿件投诉,请联系:editor@netbroad.com
觉得内容不错的朋友,别忘了一键三连哦!
赞 2
收藏 2
关注 115
成为作者 赚取收益
全部留言
0/200
成为第一个和作者交流的人吧