最近使用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进行软件开发过程中,会遇到很多奇怪的问题,遇到相同问题的概率太低了,更多具有参考的是分析思路,而非题目本身。分享快乐。