iOS 15 Crash when initialize NSAttributedString with HTML string
Asked Answered
S

2

21

I have an extension to convert HTML string to NSAttributedString.

After iOS 15 is released, I've seen a lot of crashes from my user. All those crashes are on iOS 15 and occur on the main thread.

Here is a typical crash report from Crashlytics.

Crashed: com.apple.main-thread
0  libsystem_platform.dylib       0x1f29d60c0 _os_unfair_lock_recursive_abort + 36
1  libsystem_platform.dylib       0x1f29d0a10 _os_unfair_lock_lock_slow + 304
2  Foundation                     0x183d5e730 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 68
3  WebCore                        0x192011004 <redacted> + 56
4  CoreFoundation                 0x182535ee8 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 28
5  CoreFoundation                 0x1825d1b9c ___CFXRegistrationPost_block_invoke + 52
6  CoreFoundation                 0x1825a4f54 _CFXRegistrationPost + 456
7  CoreFoundation                 0x18254bd54 _CFXNotificationPost + 716
8  Foundation                     0x183d50028 -[NSNotificationCenter postNotificationName:object:userInfo:] + 96
9  Foundation                     0x183dc89d4 NSProcessInfoNotifyPowerState + 188
10 Foundation                     0x183d5e768 -[NSProcessInfo(NSProcessInfoHardwareState) isLowPowerModeEnabled] + 124
11 WebCore                        0x191595118 <redacted> + 96
12 WebCore                        0x19201116c WebCore::LowPowerModeNotifier::LowPowerModeNotifier(WTF::Function<void (bool)>&&) + 52
13 WebCore                        0x192f36c4c WebCore::Page::Page(WebCore::PageConfiguration&&) + 1848
14 WebKitLegacy                   0x1a605ae34 -[WebView(WebPrivate) _commonInitializationWithFrameName:groupName:] + 3060
15 WebKitLegacy                   0x1a605a214 -[WebView(WebPrivate) _initWithFrame:frameName:groupName:] + 116
16 UIFoundation                   0x18d306028 -[NSHTMLReader _loadUsingWebKit] + 832
17 UIFoundation                   0x18d30715c -[NSHTMLReader attributedString] + 32
18 UIFoundation                   0x18d2c04e8 _NSReadAttributedStringFromURLOrData + 8420
19 UIFoundation                   0x18d2be378 -[NSAttributedString(NSAttributedStringUIFoundationAdditions) initWithData:options:documentAttributes:error:] + 156
20 MyAppExtensions                 0x108aa0fc4 _hidden#912_ + 4374482884 (__hidden#360_:4374482884)
21 MyAppExtensions                 0x108aa0894 NSAttributedString.init(htmlString:font:useDocumentFontSize:) + 36 (__hidden#925_:36)
22 MyAppName                           0x1045eca18 {foo_class}.convertHTML(_:) + 670 (xxxx.swift:670)
23 MyAppName                           0x1045e5c58 {foo_class}.some_function_3 + 620 (xxxx.swift:620)
24 MyAppName                           0x1045e4760 {foo_class}.some_function_2 + 212 (xxxx.swift:212)
25 MyAppName                           0x1045e4200 {foo_class}.some_function_1 + 138 (xxxx.swift:138)
.
.
.
42 UIKitCore                      0x184b5e1d0 _UIGestureRecognizerSendTargetActions + 116
43 UIKitCore                      0x184b2705c _UIGestureRecognizerSendActions + 284
44 UIKitCore                      0x184b60580 -[UIGestureRecognizer _updateGestureForActiveEvents] + 636
45 UIKitCore                      0x184b186fc _UIGestureEnvironmentUpdate + 1988
46 CoreFoundation                 0x18254c570 __CFRUNLOOP_IS_CALLING_OUT_TO_AN_OBSERVER_CALLBACK_FUNCTION__ + 36
47 CoreFoundation                 0x18251b854 __CFRunLoopDoObservers + 572
48 CoreFoundation                 0x1825168ec __CFRunLoopRun + 1052
49 CoreFoundation                 0x18252a3c8 CFRunLoopRunSpecific + 600
50 GraphicsServices               0x19dd3b38c GSEventRunModal + 164
51 UIKitCore                      0x184ed00bc -[UIApplication _run] + 1100
52 UIKitCore                      0x184c4dbe8 UIApplicationMain + 2124
53 libswiftUIKit.dylib            0x199afe184 UIApplicationMain(_:_:_:_:) + 104
54 MyAppName                      0x1043a5894 main + 7 (main.swift:7)
55 dyld                           0x106b81a24 start

The following is code of converting HTML to NSAttributedString:

extension NSAttributedString {
  convenience public init(htmlString html: String, font: UIFont? = nil, useDocumentFontSize: Bool = true) throws {
    let options: [NSAttributedString.DocumentReadingOptionKey: Any] = [
      .documentType: NSAttributedString.DocumentType.html,
      .characterEncoding: String.Encoding.utf8.rawValue
    ]

    guard let data = html.data(using: .utf8, allowLossyConversion: true) else {
      self.init(string: "")
      return
    }

    guard let fontFamily = font?.familyName else {
      try self.init(data: data, options: options, documentAttributes: nil)
      return
    }

    let attr = try NSMutableAttributedString(data: data, options: options, documentAttributes: nil)

    let fontSize: CGFloat? = useDocumentFontSize ? nil : font!.pointSize
    let range = NSRange(location: 0, length: attr.length)
    attr.enumerateAttribute(.font, in: range, options: .longestEffectiveRangeNotRequired) { attrib, range, _ in
      if let htmlFont = attrib as? UIFont {
        let traits = htmlFont.fontDescriptor.symbolicTraits
        var descrip = htmlFont.fontDescriptor.withFamily(fontFamily)

        if (traits.rawValue & UIFontDescriptor.SymbolicTraits.traitBold.rawValue) != 0 {
          descrip = descrip.withSymbolicTraits(.traitBold)!
        }

        if (traits.rawValue & UIFontDescriptor.SymbolicTraits.traitItalic.rawValue) != 0 {
          descrip = descrip.withSymbolicTraits(.traitItalic)!
        }

        attr.addAttribute(.font, value: UIFont(descriptor: descrip, size: fontSize ?? htmlFont.pointSize), range: range)
      }
    }

    self.init(attributedString: attr)
  }

Btw, I'm using Xcode 12.5 to archive the release build.

Spokane answered 27/9, 2021 at 1:14 Comment(8)
I don't have an answer yet, but we build SDKs, and one of our customers has seen this exact crash because our SDK is using the low power mode notifications. We believe this is definitely an iOS 15 bug, but don't have any definite ways to reproduce it yet. I'll post back if we do find anything.Essen
@Essen Thanks. I am still trying to reproduce it and find out if there is a way to avoid it.Spokane
I'm getting exactly the same crash here. I haven't been able to reproduce it yet. Confirming that the crash only happens on iOS 15, according to Firebase logs.Sappington
Any luck with reproducing above issue?Goose
Same issue happening to my app, still not been able to replicate.Laceylach
I am also facing this issue on iOS 15 only. Any luck with reproducing this issue @ChenZhengHawaii
Do you have HTML string? Could you post it here as well?Potter
I am also facing same issue but cannot reproduce it, crash logs are only from firebase.... any luck?Pitterpatter
C
2

Discussion about this crash in the apple developer forum here:

You might need to avoid using NSAttributedString(data: , options: [.documentType: NSAttributedString.DocumentType.html] itself and parse the HTML string to generate attribute string by yourself. Perhaps,you can use some open-source projects on GitHub such as DTCoreText.

Chaw answered 11/10, 2021 at 2:25 Comment(0)
S
0

Malloc Stack Logging In case it's useful to anyone, disabling Malloc Stack Logging no longer causes my device to crash. Edit Scheme -> Diagnostics -> Uncheck the box.

Shaveling answered 15/5, 2024 at 1:30 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.