日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當(dāng)前位置:首頁 > > 程序員寫個解
[導(dǎo)讀]在我看來最不值得一提的BUG是那種可以重復(fù)復(fù)現(xiàn)的,他的穩(wěn)定復(fù)現(xiàn)通常排查起來沒啥技術(shù)含量, 早些年我處理一個不值得一提的BUG,BUG也很好復(fù)現(xiàn),難點是復(fù)現(xiàn)時間固定在4小時左右,BUG由于文件資源未釋放引起進程訪問文件數(shù)目受限而崩潰,早期Android系統(tǒng)用該BUG獲取到root權(quán)限, 本文向你分享,如何根據(jù)錯誤提示和參考手冊找到故障點,指導(dǎo)新碼農(nóng)如何正確閱讀Linux幫助手冊(man page), 最后總結(jié)我的排查過程給小白一點實用的建議。好下面開始不如步入正題。需要調(diào)試的是一個監(jiān)控程序,代碼非常簡單,2個線程執(zhí)行不同的任務(wù),每個任務(wù)都是間隔15秒執(zhí)行一次,程序固定在大約4小時后崩潰。代碼簡單到用不著任何同步機制、沒有任何通信,極少的內(nèi)存訪問,按理來說他就不應(yīng)該存在BUG,然而還是發(fā)生了。

最不值得一提的BUG

在我看來最不值得一提的BUG是那種可以重復(fù)復(fù)現(xiàn)的,他的穩(wěn)定復(fù)現(xiàn)通常排查起來沒啥技術(shù)含量, 早些年我處理一個不值得一提的BUG,BUG也很好復(fù)現(xiàn),難點是復(fù)現(xiàn)時間固定在4小時左右,BUG由于文件資源未釋放引起進程訪問文件數(shù)目受限而崩潰,早期Android系統(tǒng)用該BUG獲取到root權(quán)限, 本文向你分享,如何根據(jù)錯誤提示和參考手冊找到故障點,指導(dǎo)新碼農(nóng)如何正確閱讀Linux幫助手冊(man page), 最后總結(jié)我的排查過程給小白一點實用的建議。好下面開始不如步入正題。需要調(diào)試的是一個監(jiān)控程序,代碼非常簡單,2個線程執(zhí)行不同的任務(wù),每個任務(wù)都是間隔15秒執(zhí)行一次,程序固定在大約4小時后崩潰。代碼簡單到用不著任何同步機制、沒有任何通信,極少的內(nèi)存訪問,按理來說他就不應(yīng)該存在BUG,然而還是發(fā)生了。

第1個4小時:縮小排查范圍,是什么引起段錯誤

在源碼若干位置加上打印執(zhí)行的函數(shù)、行號, 打開調(diào)試選項重新編譯應(yīng)用程序,開啟coredump選項,耐心等待4小時后故障復(fù)現(xiàn)。gdb打開coredump 確認(rèn)段錯誤(Segmentation fault),棧溯確認(rèn)崩潰現(xiàn)場調(diào)用棧。段錯誤位于ti_ck_mutil函數(shù)第266行之后。
TickStatusIO():105ti_ck_mutil():266Segmentation fault (core dumped) (gdb) bt#0  0x401b28e0 in vfwprintf () from /lib/libc.so.6#1  0x00009d10 in ti_ck_mutil (cmdstr=0xbebffa4c, len=1) at src/ti.c:268#2  0x00008e2c in TickStatusIO () at src/initgpio.c:106#3  0x00009238 in main (argc=1, argv=0xbebffbf4) at src/initgpio.c:304

審查ti_ck_mutil函數(shù)內(nèi)226行之后的代碼,結(jié)合棧底位置是vfwprintf函數(shù)入口,基本可以確定導(dǎo)致崩潰位置是fread函數(shù),fread可能會有什么錯誤呢?
int ti_ck_mutil(char *cmdstr, int count){ FILE *stream; char strout[256]; int ret, failcount = 0;  for (int i = 0; i < count; i++) { printf("%s()%d\n", __FUNCTION__, __LINE__);//226行 stream = popen(cmdstr, "r");//未檢查文件是否成功 ret = fread(strout, sizeof(char), sizeof(strout), stream); // 228行  strout[ret] = '\0'; pclose(stream); // ... } return failcount;}
fread輸入?yún)?shù)只有4個,猜測可能存在的失敗原因有3點:
1、被編譯器優(yōu)化后strout的緩存不是256

但后面用的是算數(shù)表達式sizeof,就算被優(yōu)化也不會造成錯誤。
觀點:暫時不去瞎想2、fread寫入最后一個字符時溢出。

strout后第256地址也被填寫了,實際我讀寫的文件不超過64byte,不應(yīng)該超過256。
即使第256地址被fread寫了,相當(dāng)于內(nèi)存訪問越接。訪問越接發(fā)生什么錯誤都不奇怪,輕微越接會影響附近變量的值,比如ret和stream的值改變,大范圍越界破壞調(diào)用棧。觀點:猜測fread可能訪問越限,但絕對沒破壞調(diào)用棧。若破壞調(diào)用棧,那么棧不會是整整齊齊打印4個函數(shù),而是輸出若干問號(“?? ()”),找不到函數(shù)名稱標(biāo)簽。
#0  0x000028e0 in ?? () #1  0x000038e8 in ?? () #2  0x000048ec in ?? () #3  0x000068e0 in ?? () #4  0x00009d10 in ti_ck_mutil (cmdstr=0xbebffa4c, len=1) at src/ti.c:268#5  0x00008e2c in TickStatusIO () at src/initgpio.c:106#6  0x00009238 in main (argc=1, argv=0xbebffbf4) at src/initgpio.c:304

3、stream文件描述符無效觀點:有可能,源碼未對popen返回結(jié)果做判斷。

第2個4小時:是內(nèi)存越界?還是資源不足?

于是結(jié)合猜測2和3,對源碼做2處理修改:1、不向fread傳遞完整內(nèi)存長度,保證最后一個字符不被fread填寫 2、判斷popen返回值
stream = popen(cmdstr, "r");ret = fread(strout, sizeof(char), sizeof(strout), stream); 修改后 stream = popen(cmdstr, "r");if (stream == 0) { perror("popen error:");}ret = fread(strout, sizeof(char), sizeof(strout) - 1, stream);

繼續(xù)等待4小時,程序依舊崩潰,輸出崩潰前提示執(zhí)行popen失敗,返回值0,錯誤原因記錄在errno里,errno指示打開太多文件,資源不足。
	
popen error:: Too many open files

機理分析:為什么文件打開太多?

進一步定位到故障點在popen函數(shù)上,問題是:啥叫文件打開太多?查看popen幫助介紹:man popen?;蛟S能給我解釋
RETURN VALUEThe popen() function returns NULL if the fork(2) or pipe(2) calls fail, or if it cannot allocate memory.
本質(zhì)上popen是個“殼",它返回0的原因有兩個:1、它間接調(diào)用fork()創(chuàng)建子進程執(zhí)行腳本,間接調(diào)用pipe()創(chuàng)建管道,子進程輸出信息從管道傳遞到父進程。2、沒有足夠的內(nèi)存分配。從第2點:沒有足夠的內(nèi)存方向去排查,無非是內(nèi)存泄漏咯,通常是申請內(nèi)存有釋放干凈導(dǎo)致。c語言標(biāo)準(zhǔn)內(nèi)存分配函數(shù)有malloc、calloc、realloc、reallocarray,對應(yīng)的釋放函數(shù)只有free。我應(yīng)該在源碼上搜索,是否所有“分配函數(shù)和釋放函數(shù)都一一配對”,哦~別忘了,小白可能還不清楚,除了常用的malloc外,還有像mmap這樣的內(nèi)存分配函數(shù),它有專用的釋放函數(shù)munmap。從搜索結(jié)果上看,數(shù)目是能對得上的,暫且粗略的判定不存內(nèi)存泄漏。更仔細的排查方向應(yīng)該是:確定代碼執(zhí)行流真的執(zhí)行到釋放函數(shù),而不是單純地看數(shù)目是否匹配



在繼續(xù)閱讀popen的errors段落描述。
ERRORSThe popen() function does not set errno if memory allocation fails. If the underlying fork(2) or pipe(2) fails, errno is set appropriately. If the type argument is invalid, and this condition is detected, errno is set to EINVAL.
popen不會因為內(nèi)存分配失敗而在errno記錄錯誤碼,如果是fork()或pipe()函數(shù)執(zhí)行失敗則在errno設(shè)置相應(yīng)錯誤碼。忙半天忙個寂寞,年輕人,別學(xué)會寫一、二、三,就自以為無師自通懂得寫四、寫一萬。讀完man全文再入手好不好!既然errno提示具體錯誤信息,就不可能是內(nèi)存泄漏,執(zhí)行失敗原因一定是Too many open files的字面意思。回想以前初學(xué)Linux時有個知識點:為了防止某用戶打開過多的文件,系統(tǒng)對進程件訪問數(shù)目有限制,默認(rèn)是10242016年4月參加宋寶華的線下培訓(xùn),他說Android剛出來時有個提權(quán)的方法(root權(quán)限):創(chuàng)建1024個無用子進程資源且不釋放,第1025個進程就能得到root權(quán)限。命令查看應(yīng)用程序運行一段時間后,有多少文件描述符號(file descriptor)沒有釋放。果然,每間隔15秒文件描述符就多一個。256分鐘后達到1024個文件描述符,時間上和軟件4小時崩潰很接近。
watch -n 1 ls -l /proc/PID/fd

再用之前的篩選方法:排查open和close的函數(shù)是一一匹配。發(fā)現(xiàn)open關(guān)鍵詞篩選出
6行,close作為關(guān)鍵詞篩出5行。opendir沒有對應(yīng)的close。


捂臉?。?!“Linux下一切皆是文件”我還沒理解透徹,沒意識到打開目錄(opendir)也是文件資源,應(yīng)用程序某線程每間隔15秒就訪問一次目錄。man opendir確認(rèn)closedir是它的配對關(guān)閉函數(shù)。
SEE ALSOopen(2), closedir(3), dirfd(3), readdir(3), rewinddir(3), scandir(3), seekdir(3), telldir(3)
添加上closedir后故障得以修復(fù)。

順帶提一下

貼圖用的搜索工具不是grep而是我自己寫的腳本jgrep,它的用法和grep完全一樣,輸入前面的數(shù)字能打開對于文件所在行,對于搜索源碼、系統(tǒng)配置文件檢索、跳轉(zhuǎn)特別適用。如果你對jgrep感興趣的話,在我的公眾號“程序員寫個解”發(fā)送 “20220411” 可獲取。




總結(jié)建議

BUG成功得以修復(fù),它本是不應(yīng)該犯的錯誤,在這里我給自己和讀者建議:1、以后使用不熟悉的API,首先查閱他的幫助手冊2、對于內(nèi)存分配函數(shù)有相互獨立的API,比如malloc對應(yīng)free、mmap對應(yīng)munmap。跟著手冊建議的API去掉釋放資源,避免不可預(yù)知的故障發(fā)生。最后,如果你覺得文章對你有所幫助,有啟發(fā)作用。歡迎點擊,把今天的內(nèi)容分享給你的好友,和他一起討論學(xué)習(xí)。
本站聲明: 本文章由作者或相關(guān)機構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: 驅(qū)動電源

在工業(yè)自動化蓬勃發(fā)展的當(dāng)下,工業(yè)電機作為核心動力設(shè)備,其驅(qū)動電源的性能直接關(guān)系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅(qū)動電源設(shè)計中至關(guān)重要的兩個環(huán)節(jié),集成化方案的設(shè)計成為提升電機驅(qū)動性能的關(guān)鍵。

關(guān)鍵字: 工業(yè)電機 驅(qū)動電源

LED 驅(qū)動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設(shè)備的使用壽命。然而,在實際應(yīng)用中,LED 驅(qū)動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設(shè)計、生...

關(guān)鍵字: 驅(qū)動電源 照明系統(tǒng) 散熱

根據(jù)LED驅(qū)動電源的公式,電感內(nèi)電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關(guān)鍵字: LED 設(shè)計 驅(qū)動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產(chǎn)業(yè)的重要發(fā)展方向。電動汽車的核心技術(shù)之一是電機驅(qū)動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅(qū)動系統(tǒng)中的關(guān)鍵元件,其性能直接影響到電動汽車的動力性能和...

關(guān)鍵字: 電動汽車 新能源 驅(qū)動電源

在現(xiàn)代城市建設(shè)中,街道及停車場照明作為基礎(chǔ)設(shè)施的重要組成部分,其質(zhì)量和效率直接關(guān)系到城市的公共安全、居民生活質(zhì)量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關(guān)鍵字: 發(fā)光二極管 驅(qū)動電源 LED

LED通用照明設(shè)計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數(shù)校正(PFC)、空間受限和可靠性等。

關(guān)鍵字: LED 驅(qū)動電源 功率因數(shù)校正

在LED照明技術(shù)日益普及的今天,LED驅(qū)動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設(shè)備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關(guān)鍵字: LED照明技術(shù) 電磁干擾 驅(qū)動電源

開關(guān)電源具有效率高的特性,而且開關(guān)電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅(qū)動電源

關(guān)鍵字: LED 驅(qū)動電源 開關(guān)電源

LED驅(qū)動電源是把電源供應(yīng)轉(zhuǎn)換為特定的電壓電流以驅(qū)動LED發(fā)光的電壓轉(zhuǎn)換器,通常情況下:LED驅(qū)動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關(guān)鍵字: LED 隧道燈 驅(qū)動電源
關(guān)閉