[iOS/OC]platform_memmove的Crash

0x0 背景

原本是放到自己博客的,不怎么用了,把文章同步过来,原文地址[iOS/OC]platform_memmove的Crash

这个问题是今年1月底排查的,gif/apng动图播放时在iOS11以下会小概率闪退。是个比较有趣的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的问题链接

SDWebImage的问题链接

该问题在Google上能搜到的结果还是不少的,但是有效信息很少。比较有用的是openradar上提到的iOS10.3beta上已经修复了该问题。可以略微松一口气,最不济可以甩锅给苹果了。甚至如果你的APP只支持iOS11(可能性不大,但是万一有呢),都可以直接忽略了。

0x1 Crash原因

虽然是系统的BUG,但是还是要搞清楚Crash的原因,尽量在业务代码上避免该问题引发其他的风险。排查过程比较艰辛,只说最终结果吧:

CGContextDrawImage();不再保证对imageRef的原子操作。
当对于1个imageRef,有多个线程并发绘制时,会触发buffer的memcmp的Crash

根据问题原因可以知道,其实该Crash在多线程同时解码同1份imageRef时才会Crash,因此如果没有引入SDWebImage/YYImage等三方图片库,系统默认主线程解码是不会有改Crash的。

另外,静图解码也是有概率Crash,但是网上反馈比较少,主要原因也是概率的问题。和一般的多线程Crash一样,次数多了概率才打,在相同的业务场景下,动图解码的频次远高于静图,因此动图更容易触发该Crash。

0x2 Crash防护

知道Crash原因后,防护相对就比较简单了,只要保证不会对同一个image资源同时解码就可以了。1个简单的方法是在解码时,使用UIImage作为input,对UIImage进行多线程保护。如:

@synchronized(image) {
    return [self decodedImageWithCGImageRef:image.CGImage];
}

你可能感兴趣的:([iOS/OC]platform_memmove的Crash)