Author: Byte Mobile Technology — Chen Yi
background
Since September last year, after many users upgraded to iOS 14, many ImageIO related stack Crash problems appeared online, and almost all apps in the company, and some apps even reached the Top 3 Crash.
Thanks to the precise data collection mechanism of APM platform and abundant anomaly information on site, we collected detailed Crash log information for analysis and solution.
Problem orientation
The stack information
From the stack information, ImageIO crashed while parsing the image information, and the last method called looks like it’s related to INameSpacePrefixMap, And the realization of the this method CGImageSourceCopyPropertiesAtIndex speculated that Crash should be concerned.
Problem aggregation characteristics
The models are concentrated in iOS14 and above and appear in the background
Analysis of the
Do a preliminary analysis from CrashLog
-
From the stack information, this code is in the photo in the child thread through analytical imageSource CGImageSourceCopyPropertiesAtIndex image information, and wild pointer Crash happened.
-
Only one input imageSource CGImageSourceCopyPropertiesAtIndex, imageSource generated by the data of the picture, the call stack is not multithreaded operations, Multiple thread operation imageSource and data can be excluded to cause Crash.
-
The stack is parsing a PNG image, and by changing the format of the sent image to JPG, it does not decrease in magnitude. Presumably Crash was not caused by a particular image format.
Disassembly analysis
Disassembly preparation
- IPhone 8 with iOS 14.3
- ImageIO system libraries: ~ / Library/Developer/Xcode/iOS DeviceSupport directory to find corresponding iOS 14.3 ImageIO
- A CrashLog of iOS 14.3 and iPhone 8
- Hopper
The disassembly
- Find instruction offset address 2555072 from CrashLog
- Open ImageIO with Hopper and jump to instruction offset address 2555072
Navigate => Go To File Offset 2555072
- The corresponding instruction to Crash should be
0000000181b09cc0 ldr x8, [x8, #0x10]
, you can see that it should be access[x8, #0x10]
There is an error pointing to memory
- Check register value in Crashlog, wrong address
far: 0x000021a1ee2fa271
And the X8 register is already an incorrect value0x000021a1ee2fa261
- Track back up to see where X8 came from
-
0000000181b09cbc LDR x8, [x20] x8 is in memory pointed to by X20 (that is, x8 = *x20)
-
0000000181b09C98 LDR X20, [x21, #0x8] x20 exists in memory pointed to by [x21, #0x8]
-
0000000181b09c8c ADRP x21, # 0x1DA0ed000, 0000000181b09c90 Add x21, x21, #0xe10 x21 points to a data segment. Either the global variable is wild, or some memory (x20) referenced by the global variable is wild
- X8, x20, x21
- X21, by its name, should be a global Map
ImageIO`AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap
Copy the code
- According to Hopper, this
sDefaultNameSpacePrefixMap
Only in the
AdobeXMPCore_Int: : ManageDefaultNameSpacePrefixMap (bool) this function call. It is possible to call this function in multiple threads, resulting in the presence of the global variable data race causing wild Pointers.
__ZZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEbE26sDefaultNameSpacePrefixMap: // AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap
00000001da0ede10 dq 0x0000000000000000 ; DATA XREF=__ZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEb+44, __ZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEb+120, __ZN16AdobeXMPCore_IntL31ManageDefaultNameSpacePrefixMapEb+392
Copy the code
- After repeated debugging at run time, this
AdobeXMPCore_Int: : ManageDefaultNameSpacePrefixMap (bool) will call in multiple methods (and add the lock, all calls are unlikely to appear 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()
- Access global variables in the background thread
sDefaultNameSpacePrefixMap
The global variable has been destructed in the main thread, and the background thread will continue to access the global variable, resulting in a wild pointer access exception. It is found that the main thread stack of Crash log also appears _exit call, which can be determined to be caused by global variable destruction.
Causes of Crash:
After the user manually killed the process, the main thread destructed the global variable, and then the child thread accessed the global variable again, resulting in a wild pointer.
Recurring problems
Try the child thread constantly invoke CFDictionaryRef CGImageSourceCopyPropertiesAtIndex (CGImageSourceRef isrc, size_t index, CFDictionaryRef options); And manually killing the process triggers the crash
Successful repetition
It can be proved that the above reasoning is correct.
conclusion
-
CFDictionaryRef CGImageSourceCopyPropertiesAtIndex(CGImageSourceRef isrc, size_t index, CFDictionaryRef options); This method will eventually access global variables while parsing part of the image
ImageIO`AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap Copy the code
-
After the user manual kill process, this sDefaultNameSpacePrefixMap destructor, if by this time the child thread to be accessed again wild pointer problems may appear
Fix ImageIO Crash scheme
Because sDefaultNameSpacePrefixMap is the global variables within the system library, can’t change them, only to avoid the child thread call CGImageSourceCopyPropertiesAtIndex method
-
Method one: CGImageSourceCopyPropertiesAtIndex is used to obtain high image width, imageOrientation, dynamic information such as photo frame, choose to replace with other methods, um participant. The width and height are obtained using CGImageRef
-
Method 2: will be calling thread CGImageSourceCopyPropertiesAtIndex convergence, call atexit function to register a callback function end of the process, the end of the process will terminate
About the Byte Mobile Platform team
Client Infrastructure, bytedance’s mobile platform team, is an industry leader in big front-end Infrastructure technology. It is responsible for the construction of big front-end Infrastructure in Bytedance’s China region to improve the performance, stability and engineering efficiency of the company’s entire product line. The supported products include but are not limited to Douyin, Toutiao, Watermelon Video, Huoshan Video, etc., and have in-depth research on mobile terminal, Web, Desktop and other terminals.
Now! Client/front-end/server/side intelligent algorithm/test development for global recruitment! Let’s change the world with technology. If you are interested, please contact [email protected] with the subject line resume – Name – Job objective – Phone number.