最近使用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進行軟件開發過程中,會遇到很多奇怪的問題,遇到相同問題的概率太低了,更多具有參考的是分析思路,而非題目本身。分享快樂。