[iOS/OC]platform_memmove的Crash

0x0 背景

原本是放到自己博客的,不怎么用了,把文章同步過(guò)來(lái),原文地址[iOS/OC]platform_memmove的Crash

這個(gè)問(wèn)題是今年1月底排查的,gif/apng動(dòng)圖播放時(shí)在iOS11以下會(huì)小概率閃退。是個(gè)比較有趣的Crash,重新記錄一下。

典型堆棧:

#13. Crashed: PINAnimatedImage disk write queue
0  libsystem_platform.dylib       0x1915d4e60 _platform_memmove + 96
1  ImageIO                        0x1943c0a74 GIFReadPlugin::copyImageBlockSet(InfoRec*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) + 3192
2  ImageIO                        0x1943c0a74 GIFReadPlugin::copyImageBlockSet(InfoRec*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) + 3192
3  ImageIO                        0x1943bf7c4 GIFReadPlugin::CopyImageBlockSetProc(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) + 124
4  ImageIO                        0x19422073c IIOImageProviderInfo::copyImageBlockSetWithOptions(CGImageProvider*, CGRect, CGSize, __CFDictionary const*) + 496
5  ImageIO                        0x19421e640 IIOImageProviderInfo::CopyImageBlockSetWithOptions(void*, CGImageProvider*, CGRect, CGSize, __CFDictionary const*) + 356
6  CoreGraphics                   0x1939eeb24 CGImageProviderCopyImageBlockSet + 220
7  CoreGraphics                   0x193c833ac imageProvider_getBytes + 88
8  CoreGraphics                   0x193ab30e0 CGDataProviderCopyData + 280
9  Pinterest                      0x100a46238 __94+[PINAnimatedImageManager processAnimatedImage:temporaryDirectory:infoCompletion:decodedPath:]_block_invoke.225 (PINAnimatedImageManager.m:397)
10 libdispatch.dylib              0x1913d21fc _dispatch_call_block_and_release + 24
11 libdispatch.dylib              0x1913d21bc _dispatch_client_callout + 16
12 libdispatch.dylib              0x1913e012c _dispatch_queue_serial_drain + 240
13 libdispatch.dylib              0x1913d59a4 _dispatch_queue_invoke + 652
14 libdispatch.dylib              0x1913e08d8 _dispatch_queue_override_invoke + 360
15 libdispatch.dylib              0x1913e234c _dispatch_root_queue_drain + 572
16 libdispatch.dylib              0x1913e20ac _dispatch_worker_thread3 + 124
17 libsystem_pthread.dylib        0x1915db2a0 _pthread_wqthread + 1288
18 libsystem_pthread.dylib        0x1915dad8c start_wqthread + 4

openradar的問(wèn)題鏈接

SDWebImage的問(wèn)題鏈接

該問(wèn)題在Google上能搜到的結(jié)果還是不少的,但是有效信息很少。比較有用的是openradar上提到的iOS10.3beta上已經(jīng)修復(fù)了該問(wèn)題??梢月晕⑺梢豢跉猓畈粷?jì)可以甩鍋給蘋(píng)果了。甚至如果你的APP只支持iOS11(可能性不大,但是萬(wàn)一有呢),都可以直接忽略了。

0x1 Crash原因

雖然是系統(tǒng)的BUG,但是還是要搞清楚Crash的原因,盡量在業(yè)務(wù)代碼上避免該問(wèn)題引發(fā)其他的風(fēng)險(xiǎn)。排查過(guò)程比較艱辛,只說(shuō)最終結(jié)果吧:

CGContextDrawImage();不再保證對(duì)imageRef的原子操作。
當(dāng)對(duì)于1個(gè)imageRef,有多個(gè)線(xiàn)程并發(fā)繪制時(shí),會(huì)觸發(fā)buffer的memcmp的Crash

根據(jù)問(wèn)題原因可以知道,其實(shí)該Crash在多線(xiàn)程同時(shí)解碼同1份imageRef時(shí)才會(huì)Crash,因此如果沒(méi)有引入SDWebImage/YYImage等三方圖片庫(kù),系統(tǒng)默認(rèn)主線(xiàn)程解碼是不會(huì)有改Crash的。

另外,靜圖解碼也是有概率Crash,但是網(wǎng)上反饋比較少,主要原因也是概率的問(wèn)題。和一般的多線(xiàn)程Crash一樣,次數(shù)多了概率才打,在相同的業(yè)務(wù)場(chǎng)景下,動(dòng)圖解碼的頻次遠(yuǎn)高于靜圖,因此動(dòng)圖更容易觸發(fā)該Crash。

0x2 Crash防護(hù)

知道Crash原因后,防護(hù)相對(duì)就比較簡(jiǎn)單了,只要保證不會(huì)對(duì)同一個(gè)image資源同時(shí)解碼就可以了。1個(gè)簡(jiǎn)單的方法是在解碼時(shí),使用UIImage作為input,對(duì)UIImage進(jìn)行多線(xiàn)程保護(hù)。如:

@synchronized(image) {
    return [self decodedImageWithCGImageRef:image.CGImage];
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容