realm-swift: Crash - Operation not permitted

We experience a extrem frequent crash since we upgraded to Realm 2.0.2. I believe this has to do something (again) with FileProtection / Background execution.

I’m not able to reproduce this locally but this affects a lot app sessions. We do have a large userbase and it seems that it affects around 15% of our users but crashes very frequently for this users.

What’s strange about this - Fabric shows 100% App In-Focus for this crash - so maybe this is during a transition from/to the background? As this crashes before we do anything in the app it’s hard to say.

Goals

We try to open the database at the very beginning of our app. We supported multiple background modes, i think this might be something with BackgroundFetch or background BT-Communication.

With 1.x everything worked as expected.

Expected Results

No crash 😉

Actual Results

What we see on Fabric: (shortened the path)

fatal error: 'try!' expression unexpectedly raised an error: 
Error Domain=io.realm Code=2 "Unable to open a realm at path 'path/db..realm.lock': open() failed: Operation not permitted." 
UserInfo={
Error Code=2, NSFilePath=path/db.realm.lock, 
Underlying=open("path/db.realm.lock") failed: Operation not permitted, 
NSLocalizedDescription=Unable to open a realm at path '/path/db.realm.lock': open() failed: Operation not permitted.
}: 
file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-800.0.46.2/src/swift/stdlib/public/core/ErrorType.swift, line 178

The stack trace is confusing and points to method-calls that can’t be called from that point, so I guess fabric records something wrong.

Crashed: db.queue
0  libswiftCore.dylib             0x10201a848 _TFs16_assertionFailedFTVs12StaticStringSSS_Su5flagsVs6UInt32_Os5Never + 164
1  libswiftCore.dylib             0x10203ac00 swift_unexpectedError_merged + 484
2  libswiftCore.dylib             0x10203aa00 swift_unexpectedError + 26
// 3 - Fabric fail? - I think this points to let _ = try! Realm(configuration: config)
3  OurApp                        0x1007ba340 static Database.(reset() -> ()).(closure #1).(closure #1) (Database.swift) 
4  libdispatch.dylib              0x1804fd1c0 _dispatch_client_callout + 16
5  libdispatch.dylib              0x18050a860 _dispatch_barrier_sync_f_invoke + 84
6  OurApp                        0x1007ba030 Database.init(databaseVersion : Int) -> Database (Database.swift)
7  OurApp                        0x1008035d0 init(databaseVersion : Int, environment : Environment)  (Database.swift:63)
8  OurApp                        0x100803f18 static setup(Int, environment : Environment) -> () (AppDelegate.swift)
9  OurApp                        0x100148000 specialized AppDelegate.application(UIApplication, didFinishLaunchingWithOptions : [UIApplicationLaunchOptionsKey : Any]?) -> Bool (AppDelegate.swift)
10 OurApp                        0x10013ebcc @objc AppDelegate.application(UIApplication, didFinishLaunchingWithOptions : [UIApplicationLaunchOptionsKey : Any]?) -> Bool (AppDelegate.swift)
11 UIKit                          0x18752f42c -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 400
12 UIKit                          0x18773fb70 -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3524
13 UIKit                          0x1877458e0 -[UIApplication _runWithMainScene:transitionContext:completion:] + 1656
14 UIKit                          0x18775a080 __84-[UIApplication _handleApplicationActivationWithScene:transitionContext:completion:]_block_invoke.3134 + 48
15 UIKit                          0x1877428c4 -[UIApplication workspaceDidEndTransaction:] + 168
16 FrontBoardServices             0x1832158bc __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 36
17 FrontBoardServices             0x183215728 -[FBSSerialQueue _performNext] + 176
18 FrontBoardServices             0x183215ad0 -[FBSSerialQueue _performNextFromRunLoopSource] + 56
19 CoreFoundation                 0x181622278 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
20 CoreFoundation                 0x181621bc0 __CFRunLoopDoSources0 + 524
21 CoreFoundation                 0x18161f7c0 __CFRunLoopRun + 804
22 CoreFoundation                 0x18154e048 CFRunLoopRunSpecific + 444
23 UIKit                          0x1875285dc -[UIApplication _run] + 608
24 UIKit                          0x187523360 UIApplicationMain + 208
25 OurApp                        0x100143aac main (AppDelegate.swift:30)
26 libdispatch.dylib              0x1805305b8 (Missing)

Steps to Reproduce

We are not able to reproduce this with an attached xcode, nor we know how to trigger this.

Code Sample

At this state nothing more than the following happend:


let config = Realm.Configuration(
            // Path
            fileURL:  dbPath,

            // Set the new schema version. This must be greater than the previously used
            // version (if you've never set a schema version before, the version is 0).
            schemaVersion: UInt64(databaseVersion)
)

let _ = try! Realm(configuration: config)

// As stated in the docs.
try! FileManager.default.setAttributes([FileAttributeKey.protectionKey : FileProtectionType.none], ofItemAtPath: realmDirectory.path)

What we tried so far

We did two emergency releases hoping we could find a workaround for this but the crash still occurs.

Emergency release 1: We set the file protection level of all Realm related files to FileProtectionType.none as first thing after app launch. - Still crashes

Emergency release 2: Also we do this on applicationWillResignActive and applicationDidBecomeActive. - Still crashes

    func fixRealmFileProtection(withBase baseDir: URL? = nil) {
        var docsDir: URL?
        if baseDir.isNil {
            docsDir = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
            docsDir?.appendPathComponent("realm")
        }
        else {
            docsDir = baseDir
        }
        if let docsDir = docsDir {
            try? FileManager.default.contentsOfDirectory(atPath: docsDir.path).forEach({ (file) in
                var fileDir = docsDir
                fileDir.appendPathComponent(file)
                var isDir: ObjCBool = false
                if FileManager.default.fileExists(atPath: fileDir.path, isDirectory: &isDir) {
                    try? FileManager.default.setAttributes([FileAttributeKey.protectionKey: FileProtectionType.none], ofItemAtPath: fileDir.path)
                    if isDir.boolValue {
                        fixRealmFileProtection(withBase: fileDir)
                    }
                }
            })
        }
    }

Version of Realm and Tooling

Realm version: 2.0.2

Xcode version: 8

iOS/OSX version: 9.3.5 - 1.1.0

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 3
  • Comments: 21 (9 by maintainers)

Most upvoted comments

We are currently rolling out a version with realm 2.1.1. Will report here if anything changes.