firebase-ios-sdk: Firestore crash / assertion failed / failed to commit transaction / collect garbage

[READ] Step 1: Are you in the right place?

  • For issues or feature requests related to the code in this repository file a Github issue.
    • If this is a feature request make sure the issue title starts with “FR:”.
  • For general technical questions, post a question on StackOverflow with the firebase tag.
  • For general Firebase discussion, use the firebase-talk google group.
  • For help troubleshooting your application that does not fall under one of the above categories, reach out to the personalized Firebase support channel.

[REQUIRED] Step 2: Describe your environment

  • Xcode version: 12.1
  • Firebase SDK version: 5.20.1
  • Firebase Component: Firestore_ (Auth, Core, Database, Firestore, Messaging, Storage, etc)
  • Component version: 1.2.1_

[REQUIRED] Step 3: Describe the problem

App crashes (as detected by Crashlytics). Apparently while in garbage collection. I have a stack trace but it doesn’t make much sense as it appears to be collection 0 garbage, and fails as operation not permitted on a file. The error and stack trace are likely the most useful items:

error:

Fatal Exception: NSInternalInconsistencyException
FIRESTORE INTERNAL ASSERTION FAILED: Failed to commit transaction: <LevelDbTransaction Collect garbage: 0 changes (0 bytes):> Failed: IO error: /var/mobile/Containers/Data/Application/919A1947-23CF-45C9-A46F-EAEAA0787A06/Documents/firestore/__FIRAPP_DEFAULT/kscoreapp/main/000015.log: Operation not permitted (expected status.ok())

stack:

Fatal Exception: NSInternalInconsistencyException
0  CoreFoundation                 0x191990518 __exceptionPreprocess
1  libobjc.A.dylib                0x190b6b9f8 objc_exception_throw
2  CoreFoundation                 0x1918aa148 +[_CFXNotificationTokenRegistration keyCallbacks]
3  Foundation                     0x1923b9f5c -[NSAssertionHandler handleFailureInFunction:file:lineNumber:description:]
4  KScoreApp                      0x100bfcfcc firebase::firestore::util::internal::Fail(char const*, char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) (hard_assert_apple.mm:34)
5  KScoreApp                      0x100bfd0e4 firebase::firestore::util::internal::Fail(char const*, char const*, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*) (hard_assert_apple.mm:54)
6  KScoreApp                      0x100c0a1b0 firebase::firestore::local::LevelDbTransaction::Commit() (leveldb_transaction.cc:211)
7  KScoreApp                      0x100bb568c -[FSTLevelDB commitTransaction] (FSTLevelDB.mm:505)
8  KScoreApp                      0x100bbeffc -[FSTLocalStore collectGarbage:] (FSTPersistence.h:216)
9  KScoreApp                      0x100bac900 std::__1::__function::__func<-[FSTFirestoreClient scheduleLruGarbageCollection]::$_3, std::__1::allocator<-[FSTFirestoreClient scheduleLruGarbageCollection]::$_3>, void ()>::operator()() (FSTFirestoreClient.mm:267)
10 KScoreApp                      0x100b71dbc firebase::firestore::util::AsyncQueue::ExecuteBlocking(std::__1::function<void ()> const&) (atomic:921)
11 KScoreApp                      0x100b84ebc firebase::firestore::util::TimeSlot::InvokedByLibdispatch(void*) (executor_libdispatch.mm:179)
12 libdispatch.dylib              0x1913d17d4 _dispatch_client_callout
13 libdispatch.dylib              0x191376018 _dispatch_continuation_pop$VARIANT$mp
14 libdispatch.dylib              0x191385fa4 _dispatch_source_invoke$VARIANT$mp
15 libdispatch.dylib              0x19137a1ec _dispatch_lane_serial_drain$VARIANT$mp
16 libdispatch.dylib              0x19137ae3c _dispatch_lane_invoke$VARIANT$mp
17 libdispatch.dylib              0x1913834a8 _dispatch_workloop_worker_thread
18 libsystem_pthread.dylib        0x1915b1114 _pthread_wqthread
19 libsystem_pthread.dylib        0x1915b3cd4 start_wqthread

Steps to reproduce:

I would love to have steps to reproduce but I haven’t seen this locally, and don’t have the logs or discussion of steps from relevant users / devices

Any instinct on how this could happen that could help me pinpoint it would be welcome

Relevant Code:

Unsure as this appears to be an internal routine. The relevant file appears to have last been edited by Grand Moff Harkin long ago and I’m not familiar enough with Firestore internals to make any guess as to possible modes of failure in a GC.

I may have missed them but I was similarly unable to find any open or closed issues in this repo that seemed relevant though I did try.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Comments: 34 (25 by maintainers)

Most upvoted comments

Sorry, as you mentioned, notching back to NSFileProtectionCompleteUntilFirstUserAuthentication instead of NSFileProtectionComplete should also work.

Other options are possible. For example if other data in your application is sensitive but your Firestore data is not, you could disable protection for just Firestore files and retain NSFileProtectionComplete for your other data.

The two workarounds cited above are for the case where you must retain NSFileProtectionComplete even for your Firestore data.

I am not sure if Firestore generates any files, but if it does, you could always change the attributes of those files to no protection and that should fix the crash too.

I ran into a very similar issue, I opened a radar on Apple today since its clearly an iOS 13 bug in my case: From my radar/Feedback:

  • An application with data protection entitlement enabled on iOS13 will crash when a user with passcode enabled locks the device while the app is running. The application must be signed, otherwise the crash is unreproducible.
  • If the user disables passcode and locks the device, no issues occur.
  • If the application isn’t signed, no issues will occur.

We reproduced this crash with our enterprise application and also with a demo app with no code in it.

As par of our troubleshooting, we realized that dyld3 is storing .closure files in the /tmp folder of the application. If we change the attributes of those files to FileAttributeKey.protectionKey: FileProtectionType.none or we just remove them after the application is launched, no crash will occur. The default attribute for FileAttributeKey.protectionKey will be FileProtectionType.complete due to the data protection entitlement.

We believe there is some sort of issue with dyld3 trying to access those files in the /tmp directory when the device is locked, and it causes the crash.

Just to be clear, to change the attributes of those files, you most likely will also need to change the posix permissions to 0o777 since most likely they are set to immutable and changing protection permissions won’t have any effect.

That’s great news.

In that case, I’m going to resolve this issue by noting that Firestore is not currently compatible with NSFileProtectionComplete.

I’ve opened #2980 to track the feature request of making it so we don’t crash by default in this mode, though there’s still not much utility to Firestore in this mode, since we can’t persist any writes submitted while file protection is active.

@mikehardy it’s NSFileProtectionComplete