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

  1. Find instruction offset address 2555072 from CrashLog

  1. Open ImageIO with Hopper and jump to instruction offset address 2555072

Navigate => Go To File Offset 2555072

  1. The corresponding instruction to Crash should be0000000181b09cc0 ldr x8, [x8, #0x10], you can see that it should be access[x8, #0x10]There is an error pointing to memory

  1. Check register value in Crashlog, wrong addressfar: 0x000021a1ee2fa271And the X8 register is already an incorrect value0x000021a1ee2fa261

  1. 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

  1. X8, x20, x21
  • X21, by its name, should be a global Map
ImageIO`AdobeXMPCore_Int::ManageDefaultNameSpacePrefixMap(bool)::sDefaultNameSpacePrefixMap
Copy the code


  1. According to Hopper, thissDefaultNameSpacePrefixMapOnly 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
  1. 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()



  1. Access global variables in the background threadsDefaultNameSpacePrefixMapThe 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.