swift-toolkit
swift-toolkit copied to clipboard
Crash when opening a book
Describe the bug
We recently released a new version that included bug fixes for iOS 18. However, after the update, we noticed a significant drop in crash-free users—over 10%. In an attempt to resolve the issue, we downgraded the Readium version to 2.6.0, which previously did not cause any crashes. Unfortunately, this did not resolve the problem. Finally, we tried building the project with Xcode 15.4 instead of Xcode 16.0, and the crash issue was eliminated.
How to reproduce?
- Open a book
Readium version
2.6.0 ... 2.7.3
OS version
Mainly iOS 17 and 18
Testing device
Any Device
Environment
macOS: 15.0
platform: x86_64
carthage: 0.40.0
Xcode 16.0
Build version 16A242d
Additional context
Crashed: com.apple.root.default-qos
0 libsystem_platform.dylib 0x2a54 platform_memmove + 52
1 libxml2.2.dylib 0x18638
You can download the crash reports here.
We are experiencing the same issue. When building with Xcode 16, some users experience the same crash. Unfortunately(?), the crash is not consistant, for some users it never crashes. I have yet to have any workaround.
I have new information about this "bug" It seems that the application only crashes in Relaese mode, so when downloaded from TestFlight. Building through xcode doesn't cause the code to crash. Any idea? I tried several combos, I tried using xcode 15.4, xcode 16, I tried using my iPhone 15 Plus and another iPhone x and even an iPhone 7. Maybe the problem is around the optimization level or something? I would be glad to hear any tip.
Okay, I found the issue. For my defense, I got this project from others and it is an old one :) It looks like the library was updated from 2.2.0 to 2.6.0 at some point without doing the 2.5.0 migratin guide. Although it worked at that time, it looks like now this is causing this crash. I changed the implementation to use the GCDHTTPServer.shared as shown in the guide and the crash seems to go away.
@grighakobian Was it the same issue as described by @tnorbert above for you?
@mickael-menu We haven't migrated to 2.5.0 yet; we're currently using version 2.7.3. Everything works fine when building on Xcode 15.4, but we're encountering crashes when building on Xcode 16.
@grighakobian Could you share your code creating an instance of EPUBNavigatorViewController? (Just all the parameters you pass to the constructor).
@grighakobian @mickael-menu So, basically, my steps were to update the library to 2.7.3 and resolve every deprecated message. This includes using a new initializer in EPUBNavigatorViewController (and switching to GCDHTTPServer.shared) and reimplementing the user preferences (saving the preferences by our own logic and applying these values directly to the reader). After these steps, all our crashed went away. Although, these changes made us rework some of our epubs as the new reader did not apply several user preferences such as font sizes. It turned out that some epubs needed to be changed.
@grighakobian Could you share your code creating an instance of
EPUBNavigatorViewController? (Just all the parameters you pass to the constructor).
@mickael-menu Here is the EPUBNavigatorViewController initialization code.
let navigatorViewController = EPUBNavigatorViewController(publication: publication, initialLocation: initialLocation, resourcesServer: publicationServer)
Note that we are using the old PublicationServer API.
Okay that's probably why this is crashing on Xcode 16. Let me know if you still have the issue after migrating the HTTP server.
@mickael-menu Unfortunately, I started getting these crashes, too. At first, I though I solved this but it looks like I was wrong. Right now, I am getting the exact same crashes as @grighakobian. Any idea on that? The user's download it from TestFlight and when the device is fully offline (airplane mode and wifi off), the app crashes when trying to open an epub.
No but it's actually crashing in one of our third-party dependencies. Maybe you can take a look on Fuzi's repository to see if something similar was mentioned, and/or open an issue there: https://github.com/cezheng/Fuzi
Please let me know if you do so I can track the answers.
The project looks pretty dead actually. Maybe it's time to look for another XML parser.
If someone wants to contribute a solution with an alternative XML parser, you need to implement the following protocol: https://github.com/readium/swift-toolkit/blob/develop/Sources/Shared/Toolkit/XML/XML.swift
Here's an example using Fuzi: https://github.com/readium/swift-toolkit/blob/develop/Sources/Shared/Toolkit/XML/Fuzi.swift
And there are tests here, you just need to copy and adjust the FuziTests class: https://github.com/readium/swift-toolkit/blob/f53630f81f75c6201c35f40082021f2e4ed42f08/Tests/SharedTests/Toolkit/XML/XMLTests.swift#L94-L107
@mickael-menu It looks like somebody opened a new issue here and it is the same fuzi crash as we are experiencing.
https://github.com/readium/swift-toolkit/issues/495
I think this is going to be a bigger issue now, I don't think that there is an easy solution but I am going to try to solve it somehow, without switching the parser (we kinda need it to be fixed asap as we are using this in production :) )
What's your plan to fix it? I guess we can't without fixing the issue in Fuzi. Forking it in Readium is a possibility if you find the solution by modifying Fuzy directly.
@mickael-menu I wrote a temporary solution in the other ticket but it is only a band aid for production crashes. @grighakobian What was your situation? Did you manage to solve this?
@tnorbert We fixed the crash by compiling the project on Xcode 15.4.
Hello everyone, Xcode 16.1 crash still happening.
I can't reproduce the crash on my device, I tried testflight builds and release build from Xcode. I tried many books of different sizes.
@grighakobian @tnorbert @mickael-menu @HadrienGardeur
I reproduced the crash on the old device (se 1 gen), Xcode 16.1, release scheme.
I tried to fix it here https://github.com/MelDev1/Fuzi
The problem was in the unsafe creation of UnsafeBufferPointer.
public convenience init(cChars: [CChar]) throws {
let buffer = cChars.withUnsafeBufferPointer { buffer in
UnsafeBufferPointer(rebasing: buffer[0..<buffer.count])
}
try self.init(buffer: buffer)
}
The documentation prohibits doing this.
Here is the quick solution:
public convenience init(cChars: [CChar]) throws {
let mutablebuffer = UnsafeMutableBufferPointer<CChar>.allocate(capacity: cChars.count)
_ = mutablebuffer.initialize(from: cChars)
defer {
mutablebuffer.deallocate()
}
let buffer = UnsafeBufferPointer(mutablebuffer)
try self.init(buffer: buffer)
}
I released the application and for the second day there have been no crashes. Please check my fix.
@MelDev1 That's great thank you! I added a comment on your PR to Fuzi to add some weight, if we have no answers from the maintainers I think I will open a fork on the readium organization to release your fix.
@MelDev1 Still no crash reports after your fix? I think it's time to consider doing a fork.
@mickael-menu yep, no crashes
Could some of you try the branch fix-fuzi based off 2.7.3 and report whether the problem is fixed for you? Thank you!
cc @MelDev1 @grighakobian @tnorbert
Not yet on 2.7.3 but changed just the Fuzi dependency to that fork and fix-tag. Playing around for about 30 minutes on two device < iOS 18 in release mode. Same scenario that was crashing constantly and pretty reliable before. So far works like a charm. ❤️👍👏