得益于 APM 平臺精準(zhǔn)數(shù)據(jù)采集機(jī)制和豐富的異常信息現(xiàn)場,我們通過收集到詳細(xì)的 Crash 日志信息進(jìn)行分析解決。
問題定位
堆棧信息
從堆棧信息看,是在 ImageIO 解析圖片信息的時候 Crash ,并且最后調(diào)用的方法都是看起來都是和 INameSpacePrefixMap 相關(guān),推測 Crash 應(yīng)該是和這個方法 CGImageSourceCopyPropertiesAtIndex 的實(shí)現(xiàn)有關(guān)。
問題聚合特點(diǎn)
機(jī)型集中在 iOS14 以上的版本,同時是在后臺出現(xiàn)
分析
從 CrashLog 做一個初步分析
img
- 從堆棧信息看,這段代碼是圖片庫在子線程通過 CGImageSourceCopyPropertiesAtIndex 解析 imageSource 中的圖片相關(guān)信息,然后發(fā)生了野指針的 Crash。
- CGImageSourceCopyPropertiesAtIndex 的輸入只有一個 imageSource,imageSource 由圖片的 data 生成,調(diào)用棧并沒有多線程操作,可以排除是多線程操作 imageSource、data 導(dǎo)致的 Crash。
- 看堆棧是在解析 PNG 圖片,通過將下發(fā)的圖片格式換成 JPG 格式,發(fā)現(xiàn)量級并沒有降低。推測 Crash 不是某種特定圖片格式引起的。
反匯編分析
反匯編準(zhǔn)備
- iOS 14.3 的 iPhone 8
- ImageIO 系統(tǒng)庫:~/Library/Developer/Xcode/iOS DeviceSupport目錄下找到對應(yīng) iOS 14.3 的 ImageIO
- 一份 iOS 14.3、iPhone 8 上發(fā)生的 CrashLog
- Hopper
反匯編
1、從 CrashLog 上找到 Crash 對應(yīng)的指令偏移地址 2555072
2、通過 Hopper 打開 ImageIO,跳轉(zhuǎn)到指令偏移地址 2555072
Navigate => Go To File Offset 2555072
3、Crash 對應(yīng)的指令應(yīng)該是0000000181b09cc0 ldr x8, [x8, #0x10],可以看到應(yīng)該是訪問 [x8, #0x10]指向的內(nèi)存出錯
4、查看 Crashlog 中對應(yīng)寄存器的值,錯誤地址 far: 0x000021a1ee2fa271,而且 x8 寄存器已經(jīng)是一個錯誤的值 0x000021a1ee2fa261
5、向上回溯查看 x8 的來源
- 0000000181b09cbc ldr x8, [x20] x8 是存在 x20 指向的內(nèi)存中(即 x8 = *x20)
- 0000000181b09c98 ldr x20, [x21, #0x8] x20 又存在[x21, #0x8] 指向的內(nèi)存中
- 0000000181b09c8c adrp x21, #0x1da0ed000,0000000181b09c90 add x21, x21, #0xe10 x21 指向的是一個 data 段,推測 x21 應(yīng)該是一個全局變量,所以,可能是這個全局變量野了,或者是這個全局變量引用的某些內(nèi)存(x20)野了
6、運(yùn)行時 debug 查看 x8、x20、x21 對應(yīng)寄存器的值是什么
- x21 從內(nèi)存地址的名字看,應(yīng)該是一個全局的 Map
ImageIO`AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap
7、從 Hopper 上看,這個sDefaultNameSpacePrefixMap只在
AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool) 這個函數(shù)中調(diào)用??赡軙诙嗑€程下調(diào)用這個函數(shù),而導(dǎo)致這個全局變量的出現(xiàn) data race 導(dǎo)致了野指針。
__ZZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEbE26sDefaultNameSpacePrefixMap:????????//?AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap
00000001da0ede10?????????dq?????????0x0000000000000000??????????????????????????;?DATA?XREF=__ZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEb+44,?__ZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEb+120,?__ZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEb+392
8、經(jīng)過在運(yùn)行時反復(fù)調(diào)試,這個
AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool) 會在多個方法中調(diào)用(并且調(diào)用時都加了鎖,不太可能會出現(xiàn) data race):
- AdobeXMPCore_Int::INameSpacePrefixMap_I::CreateDefaultNameSpacePrefixMap()
- AdobeXMPCore_Int::INameSpacePrefixMap_I::InsertInDefaultNameSpacePrefixMap(char const*, unsigned long long, char const*, unsigned long long)
- AdobeXMPCore_Int::INameSpacePrefixMap_I::DestroyDefaultNameSapcePrefixMap()
9、在后臺線程訪問訪問全局變量 sDefaultNameSpacePrefixMap 時 Crash,推測可能是用戶手動殺進(jìn)程后,全局變量在主線程已經(jīng)被析構(gòu),后臺線程還會繼續(xù)訪問這個全局變量,從而出現(xiàn)野指針訪問異常。發(fā)現(xiàn) Crash 日志的主線程堆棧也出現(xiàn) _exit 的調(diào)用,可以確定是全局變量析構(gòu)導(dǎo)致。
Crash 發(fā)生的原因:
在用戶手動殺進(jìn)程后,主線程將這個全局變量析構(gòu)了,這時候子線程再訪問這個全局變量就出現(xiàn)了野指針。
復(fù)現(xiàn)問題
嘗試在子線程不斷調(diào)用 CFDictionaryRef CGImageSourceCopyPropertiesAtIndex(CGImageSourceRef isrc, size_t index, CFDictionaryRef options);,并且手動殺掉進(jìn)程觸發(fā)這個 crash
成功復(fù)現(xiàn)
可以證明上述的推理是正確的。
總結(jié)
- CFDictionaryRef CGImageSourceCopyPropertiesAtIndex(CGImageSourceRef isrc, size_t index, CFDictionaryRef options); 這個方法在解析部分圖片的時候最終會訪問全局變量ImageIO`AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap
- 在用戶手動殺進(jìn)程后,這個sDefaultNameSpacePrefixMap被析構(gòu),如果這時候在子線程再被訪問就可能出現(xiàn)野指針的問題
修復(fù) ImageIO Crash 方案
因?yàn)閟DefaultNameSpacePrefixMap 是在系統(tǒng)庫內(nèi)部的全局變量,沒辦法對其進(jìn)行修改,只能避免在子線程調(diào)用 CGImageSourceCopyPropertiesAtIndex 方法
- 方法一:CGImageSourceCopyPropertiesAtIndex 是用來獲取圖片的寬高、imageOrientation、動圖幀等信息,選擇用其他方法來替換,e.g. 寬高用 CGImageRef 來獲取
- 方法二:將 CGImageSourceCopyPropertiesAtIndex 被調(diào)用的線程收斂起來,調(diào)用atexit函數(shù)來注冊一個進(jìn)程結(jié)束回調(diào)函數(shù),進(jìn)程結(jié)束的時候?qū)⒔K止線程
關(guān)于字節(jié)移動平臺團(tuán)隊(duì)
字節(jié)跳動移動平臺團(tuán)隊(duì)(Client Infrastructure)是大前端基礎(chǔ)技術(shù)行業(yè)領(lǐng)軍者,負(fù)責(zé)整個字節(jié)跳動的中國區(qū)大前端基礎(chǔ)設(shè)施建設(shè),提升公司全產(chǎn)品線的性能、穩(wěn)定性和工程效率,支持的產(chǎn)品包括但不限于抖音、今日頭條、西瓜視頻、火山小視頻等,在移動端、Web、Desktop等各終端都有深入研究。
就是現(xiàn)在!客戶端/前端/服務(wù)端/端智能算法/測試開發(fā) 面向全球范圍招聘!一起來用技術(shù)改變世界,感興趣可以聯(lián)系郵箱 c,郵件主題 簡歷-姓名-求職意向-電話。
1.《關(guān)于ios120幀加超高清代碼我想說手把手教你 Debug—iOS 14 ImageIO Crash 分析》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識,僅代表作者本人觀點(diǎn),與本網(wǎng)站無關(guān),侵刪請聯(lián)系頁腳下方聯(lián)系方式。
2.《關(guān)于ios120幀加超高清代碼我想說手把手教你 Debug—iOS 14 ImageIO Crash 分析》僅供讀者參考,本網(wǎng)站未對該內(nèi)容進(jìn)行證實(shí),對其原創(chuàng)性、真實(shí)性、完整性、及時性不作任何保證。
3.文章轉(zhuǎn)載時請保留本站內(nèi)容來源地址,http://f99ss.com/lishi/2117940.html