這篇文章主要講解了“怎么解決在feature/query分支上,在community倉(cāng)庫(kù),執(zhí)行以下腳本,出現(xiàn)Crash問題”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“怎么解決在feature/query分支上,在community倉(cāng)庫(kù),執(zhí)行以下腳本,出現(xiàn)Crash問題”吧!
成都創(chuàng)新互聯(lián)主要從事網(wǎng)站制作、成都網(wǎng)站制作、網(wǎng)頁(yè)設(shè)計(jì)、企業(yè)做網(wǎng)站、公司建網(wǎng)站等業(yè)務(wù)。立足成都服務(wù)張家川回族自治,十年網(wǎng)站建設(shè)經(jīng)驗(yàn),價(jià)格優(yōu)惠、服務(wù)專業(yè),歡迎來電咨詢建站服務(wù):028-86922220
在feature/query分支上,在community倉(cāng)庫(kù),執(zhí)行以下腳本,出現(xiàn)Crash。
./test.sh -f general/parser/col_arithmetic_operation.sim
我登錄到指定的機(jī)器,查看了 core dump, 確實(shí)如此。Call Stack 截圖如下:
第一步:看哪個(gè)地方 crash。是 shash.c:250 行,使用 GDB 命令 “f 1″ 查看 stack 1,查看*pObj,一下就看到 hashFp 為 NULL,自然會(huì) crash。但為什么會(huì)設(shè)置為空?其他參數(shù)呢?dataSize 設(shè)為 0 也一定是錯(cuò)的。因此可以斷定,這個(gè)結(jié)構(gòu)體是不對(duì)的。我們需要看上一層調(diào)用是否傳入了正確的參數(shù)。
第二步:使用 GDB “f 2″查看 stack 2,rpcMain.c:605 行,查看*pRpc,這些結(jié)構(gòu)體里的參數(shù)顯得很正常,包括指向 hash 的指針值看不出有什么問題。那因此可以斷定調(diào)用是 OK 的,調(diào)用 taosGetStrHashData 應(yīng)該提供了正確的參數(shù)。
第三步:既然參數(shù)對(duì)的,看 shash.c 的程序,那只可能是 SHashObj 這個(gè)結(jié)構(gòu)體已經(jīng)被釋放,訪問的時(shí)候,自然無效。再看代碼,只有一個(gè)可能,函數(shù) taosCleanUpStrHash 被調(diào)用,因此我在改函數(shù)里馬上加上一行打印日志(注意 TDengine 的日志輸出控制,系統(tǒng)配置文件 taos.cfg 里參數(shù) asyncLog 要設(shè)置為 1,否則 crash 時(shí),有可能日志不打印出來)。重新運(yùn)行腳本,查看日志,發(fā)現(xiàn) taosCleanUpStrHash 沒有被調(diào)用過。那么現(xiàn)在只有一個(gè)可能,這一塊數(shù)據(jù)的內(nèi)存被其他線程寫壞。
第四步:萬幸,我們有很棒的運(yùn)行時(shí)內(nèi)存檢查工具 valgrind, 可以通過運(yùn)行它來找找蛛絲馬跡。一運(yùn)行(valgrind 有很多選項(xiàng),我運(yùn)行的是 valgrind –leak-check=yes –track-origins=yes taosd -c test/dnode1/cfg),一下就發(fā)現(xiàn)有 invalid write,截圖如下:
第五步 :一看 valgrind 輸出,就知道 rpcMain.c:585 有 invalid write, 這里是 memcpy。從編碼上來看,這應(yīng)該沒有問題,因?yàn)榭截惖氖枪潭ù笮〉慕Y(jié)構(gòu)體 SRpcConn,每次運(yùn)行到這里都會(huì)執(zhí)行的。那么唯一的可能就是 pConn 指向的是無效的內(nèi)存區(qū),那 pConn 怎么可能是無效的?我們看一下程序:
看 584 行,pConn = pRpc->connList + sid。這個(gè) sid 是 taosAllocateId 分配出來的。如果 sid 超過 pRpc->sessions,那 pConn 毫無疑問就指向了無效的區(qū)域。那怎么確認(rèn)呢?
第六步:加上日志 578 行,分配出的 ID 打印出來,編譯,重新運(yùn)行測(cè)試腳本。
第七步:crash,看日志,可以看到 sid 能輸出到 99(max 是 100),還一切正常,但之后就崩潰。因此可以斷言,就是由于分配的 ID 超過了 pRpc→session。
第八步:查看分配 ID 的程序 tidpool.c,一看就知道原因,ID 分配是從 1 到 MAX,而 RPC 模塊只能使用 1 到 Max-1。這樣當(dāng) ID 返回為 max 時(shí),RPC 模塊自然會(huì)產(chǎn)生 invalid write。
既然知道原因,那就很好辦,有兩套方法:
1. 在 tidpool.c,taosInitIdPool 里,將 maxId 減一,這樣分配的 ID 只會(huì)是 1 到 max-1。
2. 在 rpcMain.c 的 rpcOpen() 函數(shù)里,將
pRpc->idPool = taosInitIdPool(pRpc->sessions);
改為
pRpc->idPool = taosInitIdPool(pRpc->sessions-1);
如果應(yīng)用要求最多 100 個(gè) session,這么改,RPC 至多創(chuàng)建 99 個(gè),為保證 100 個(gè),再將
pRpc->sessions = pInit->sessions;
改為
pRpc->sessions = pInit→sessions+1;
兩種方法,都重新編譯,運(yùn)行測(cè)試腳本通過,crash 不再發(fā)生。
遇到內(nèi)存被寫壞的場(chǎng)景,一定要用 valgrind 跑一次,看是否有 invalid write。因?yàn)樗且粋€(gè)動(dòng)態(tài)檢查工具,報(bào)的錯(cuò)誤都應(yīng)該是對(duì)的。只有把 invalid write 先解決,再去看 crash 問題。
這個(gè) BUG 的核心是由于 tidpool.c 分配的 ID 范圍 是 1 到 max,而 RPC 模塊假設(shè)的 ID 分配是 1 到 max-1。因此是模塊之間的約定出了問題。
感謝各位的閱讀,以上就是“怎么解決在feature/query分支上,在community倉(cāng)庫(kù),執(zhí)行以下腳本,出現(xiàn)Crash問題”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)怎么解決在feature/query分支上,在community倉(cāng)庫(kù),執(zhí)行以下腳本,出現(xiàn)Crash問題這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!