最近使用RTthread用于驅(qū)動esp32聯(lián)網(wǎng)過程中遇到了一個嚴(yán)重bug,剛開始并不曉得問題是出自哪里,煩惱三千絲。(唉,并不是系統(tǒng)提供的庫就沒有問題,一不小心在收集bug完善庫的路上漸行漸遠(yuǎn)。。。)
先看下finsh后臺給出的錯誤提示信息:
一、hard fault初步分析:
首先一點(diǎn),這是個hard fault故障,也就是線程飛走了(可能出現(xiàn)的錯誤:指針出錯or內(nèi)存溢出),出現(xiàn)的線程是clktask(這是一個灰常的重要的提示,幫你鎖定執(zhí)行過程中出錯的線程)。
上面還有一條提示執(zhí)行AT+CIPDOMIAN=XXX網(wǎng)站錯誤,這條AT指令提示很重要,含義是域名解析失敗。
最大的難題,上面的故障并不是每次都出現(xiàn),這就給解決問題帶來了很大的困擾。因?yàn)榇蟛糠謺r間都是連接網(wǎng)絡(luò)都是正常的,那么該怎樣復(fù)現(xiàn)這個故障才是最重要的,只有每次都能模擬出該故障,才能進(jìn)一步分析。
二、hard fault模擬再現(xiàn):
有一個點(diǎn)要注意就是,每次發(fā)生hard fault 都會伴隨有執(zhí)行AT+CIPDOMIAN=XXX失敗,也就是域名解析失敗,如何模擬域名解析失敗,首先你要了解一個點(diǎn),esp32的域名解析服務(wù)ip就是其自身,也就是dns的ip應(yīng)該與esp32的ip是重合的,這一點(diǎn)驗(yàn)證也很簡單,通過執(zhí)行ipconfig看看打印信息就可以確定。
接下來就是要模擬AT+CIPDOMAIN=XXX失敗的情況,可以將ESP32連接路由器網(wǎng)絡(luò)斷開,這樣相當(dāng)于ESP32處于局域網(wǎng)的狀態(tài),這個時候執(zhí)行AT+CIPDOMAIN=XXX就是failed狀態(tài),再執(zhí)行完成后,返回的就是失敗狀態(tài),實(shí)際模擬過程中也出現(xiàn)了,能確認(rèn)百分百模擬出hard fault以后,就要進(jìn)入調(diào)試階段了。
三、hard fault調(diào)試階段:
進(jìn)入全仿真,通過斷點(diǎn)調(diào)試,大概鎖定clktask線程中,發(fā)生hard fault的函數(shù),通過單步調(diào)試發(fā)現(xiàn),最終執(zhí)行函數(shù)路徑為:rt_tcpclient_start——》socket_init——》Gethostbyname;
真正導(dǎo)致hard fault的位置是socket_init函數(shù)中:dst_addr.sin_addr = *((struct in_addr *)hostname->h_addr);
因?yàn)橥ㄟ^ hostname = gethostbyname(url);返回的hostname為NULL,所以對空指針進(jìn)行操作,直接導(dǎo)致hard fault。
四、基于hostname為NULL,進(jìn)行程序改進(jìn):
基于以上的問題點(diǎn),對tcpclient.c文件進(jìn)行了局部改進(jìn)后,完美解決hard fault問題,改進(jìn)如下:
基于rtthread進(jìn)行軟件開發(fā)過程中,會遇到很多奇怪的問題,遇到相同問題的概率太低了,更多具有參考的是分析思路,而非題目本身。分享快樂。