realm-swift: mutex lock failed: Invalid argument while releasing Realm

It’s the same issue as #6686.

I already updated to 10.1.4 but still got these error reports every day. The difference is that it’s now crashing after I inserted new data into the table. It crashed after I deleted data when I was using Realm 5.4.4.

Actual Results

Fatal Exception: std::__1::system_error
mutex lock failed: Invalid argument
Fatal Exception: std::__1::system_error

com.google.firebase.crashlytics.ios.exception
0x0000000000000000
Crashed: com.google.firebase.crashlytics.ios.exception
0  pitt                           0x102656924 FIRCLSProcessRecordAllThreads + 392 (FIRCLSProcess.c:392)
1  pitt                           0x102656d08 FIRCLSProcessRecordAllThreads + 423 (FIRCLSProcess.c:423)
2  pitt                           0x10264d680 FIRCLSHandler + 34 (FIRCLSHandler.m:34)
3  pitt                           0x102649390 __FIRCLSExceptionRecord_block_invoke + 218 (FIRCLSException.mm:218)
4  libdispatch.dylib              0x1a30c3524 _dispatch_client_callout + 16
5  libdispatch.dylib              0x1a30a71fc _dispatch_lane_barrier_sync_invoke_and_complete + 56
6  pitt                           0x102648b28 FIRCLSExceptionRecord + 225 (FIRCLSException.mm:225)
7  pitt                           0x1026487c8 FIRCLSTerminateHandler() + 285 (FIRCLSException.mm:285)
8  libc++abi.dylib                0x1a31c614c std::__terminate(void (*)()) + 16
9  libc++abi.dylib                0x1a31c60e4 std::terminate() + 44
10 Realm                          0x1049f2190 __clang_call_terminate + 10
11 Realm                          0x104d999f0 realm::Group::detach() + 118
12 Realm                          0x104da36c4 realm::Transaction::close() + 60
13 Realm                          0x104da6350 TransactionDeleter(realm::Transaction*) + 20
14 Realm                          0x104dab360 std::__1::__shared_ptr_pointer<realm::Transaction*, void (*)(realm::Transaction*), std::__1::allocator<realm::Transaction> >::__on_zero_shared() + 20
15 Realm                          0x1049f4da0 std::__1::shared_ptr<realm::app::App>::~shared_ptr() + 64
16 Realm                          0x104b56980 realm::Realm::~Realm() + 96
17 Realm                          0x1049f4da0 std::__1::shared_ptr<realm::app::App>::~shared_ptr() + 64
18 libobjc.A.dylib                0x1a311ec90 object_cxxDestructFromClass(objc_object*, objc_class*) + 112
19 libobjc.A.dylib                0x1a3132cc4 objc_destructInstance + 88
20 libobjc.A.dylib                0x1a313973c _objc_rootDealloc + 52
21 Realm                          0x104b358b0 -[RLMRealm dealloc] + 92
22 libobjc.A.dylib                0x1a313c04c AutoreleasePoolPage::releaseUntil(objc_object**) + 180
23 libobjc.A.dylib                0x1a313bf44 objc_autoreleasePoolPop + 224
24 libswiftObjectiveC.dylib       0x1da16fbd8 autoreleasepool<A>(invoking:) + 68
25 pitt                           0x1024af36c closure #1 in PageCacheService.insert(caches:) + 4379505516 (<compiler-generated>:4379505516)
26 pitt                           0x1024cf51c thunk for @escaping @callee_guaranteed () -> () + 4379637020 (<compiler-generated>:4379637020)
27 libdispatch.dylib              0x1a30c29a8 _dispatch_call_block_and_release + 24
28 libdispatch.dylib              0x1a30c3524 _dispatch_client_callout + 16
29 libdispatch.dylib              0x1a30a0b3c _dispatch_lane_serial_drain$VARIANT$armv81 + 564
30 libdispatch.dylib              0x1a30a154c _dispatch_lane_invoke$VARIANT$armv81 + 396
31 libdispatch.dylib              0x1a30aa84c _dispatch_workloop_worker_thread + 580
32 libsystem_pthread.dylib        0x1a3114b74 _pthread_wqthread + 272
33 libsystem_pthread.dylib        0x1a3117740 start_wqthread + 8

Here’s another report which is similar to this issue. But there’s no any method from my codes in the callstack.

Fatal Exception: std::__1::system_error
mutex lock failed: Invalid argument
Fatal Exception: std::__1::system_error

com.google.firebase.crashlytics.ios.exception
0x0000000000000000
Crashed: com.google.firebase.crashlytics.ios.exception
0  pitt                           0x105302924 FIRCLSProcessRecordAllThreads + 392 (FIRCLSProcess.c:392)
1  pitt                           0x105302d08 FIRCLSProcessRecordAllThreads + 423 (FIRCLSProcess.c:423)
2  pitt                           0x1052f9680 FIRCLSHandler + 34 (FIRCLSHandler.m:34)
3  pitt                           0x1052f5390 __FIRCLSExceptionRecord_block_invoke + 218 (FIRCLSException.mm:218)
4  libdispatch.dylib              0x1b201d5ac _dispatch_client_callout + 20
5  libdispatch.dylib              0x1b202a360 _dispatch_lane_barrier_sync_invoke_and_complete + 60
6  pitt                           0x1052f4b28 FIRCLSExceptionRecord + 225 (FIRCLSException.mm:225)
7  pitt                           0x1052f47c8 FIRCLSTerminateHandler() + 285 (FIRCLSException.mm:285)
8  libc++abi.dylib                0x1b213540c std::__terminate(void (*)()) + 20
9  libc++abi.dylib                0x1b2135398 std::terminate() + 44
10 Realm                          0x1076aa190 __clang_call_terminate + 10
11 Realm                          0x107a519f0 realm::Group::detach() + 118
12 Realm                          0x107a5b6c4 realm::Transaction::close() + 60
13 Realm                          0x107a5e350 TransactionDeleter(realm::Transaction*) + 20
14 Realm                          0x107a63360 std::__1::__shared_ptr_pointer<realm::Transaction*, void (*)(realm::Transaction*), std::__1::allocator<realm::Transaction> >::__on_zero_shared() + 20
15 Realm                          0x1076acda0 std::__1::shared_ptr<realm::app::App>::~shared_ptr() + 64
16 Realm                          0x10780e980 realm::Realm::~Realm() + 96
17 Realm                          0x1076acda0 std::__1::shared_ptr<realm::app::App>::~shared_ptr() + 64
18 libobjc.A.dylib                0x1b208fd38 object_cxxDestructFromClass(objc_object*, objc_class*) + 116
19 libobjc.A.dylib                0x1b20a4020 objc_destructInstance + 92
20 libobjc.A.dylib                0x1b20aa8e8 _objc_rootDealloc + 60
21 Realm                          0x1077ed8b0 -[RLMRealm dealloc] + 92
22 libobjc.A.dylib                0x1b20ad380 AutoreleasePoolPage::releaseUntil(objc_object**) + 184
23 libobjc.A.dylib                0x1b20ad26c objc_autoreleasePoolPop + 232
24 libdispatch.dylib              0x1b201d588 _dispatch_last_resort_autorelease_pool_pop + 44
25 libdispatch.dylib              0x1b20244f0 _dispatch_lane_invoke + 488
26 libdispatch.dylib              0x1b202da5c _dispatch_workloop_worker_thread + 584
27 libsystem_pthread.dylib        0x1b2083718 _pthread_wqthread + 276
28 libsystem_pthread.dylib        0x1b20899c8 start_wqthread + 8

Steps for others to Reproduce

Use autoreleasepool in DispatchQueue.

Code Sample

    public func insert(caches c: [String:[MemoryCache]]?){
        guard let caches = c, !caches.isEmpty else {
            logHelper.i("Memory cache is empty.")
            return
        }

        autoreleasepool{ [weak self] in
            do {
                RealmCacheHelper.shared.invalidateSemaphore.wait()

                let logHelper = LogHelper(subsystem: "PageCacheService", category: "insertCache")

                var backgroundTaskID: UIBackgroundTaskIdentifier?

                // Request the task assertion and save the ID.
                backgroundTaskID = UIApplication.shared.beginBackgroundTask (withName: "PageCache insertion task.") {
                    logHelper.w("Background task expired.")
                    // End the task if time expires.
                    UIApplication.shared.endBackgroundTask(backgroundTaskID!)
                    backgroundTaskID = .invalid
                }

                defer{
                    RealmCacheHelper.shared.invalidateSemaphore.signal()
                    logHelper.i("Background task finished.")
                    UIApplication.shared.endBackgroundTask(backgroundTaskID!)
                    backgroundTaskID = .invalid
                }

                var memoryCaches: [MemoryCache] = caches.flatMap{ $0.value }

                logHelper.i("Making memory caches persisted \(memoryCaches.count).")

                let _realm = try RealmCacheHelper.shared.realm()

                _realm.beginWrite()

                for memoryCache in memoryCaches {
                    guard let mid = self?.getWorkerThreadMID(_realm) else {
                        return
                    }

                    let cache = MatrixCache.newInstance(
                            id: mid,
                            controllerId: memoryCache.controllerId,
                            page: memoryCache.page)

                    cache.content = memoryCache.matrixJson
                    cache.font = memoryCache.fontJson

                    _realm.add(cache)
                }

                try _realm.commitWrite()

                logHelper.i("All caches are persisted.")
            }
            catch {
                let logHelper = LogHelper(subsystem: "PageCacheService", category: "insertMatrixCache")
                logHelper.e("Failed to save page cache, error = %@", error: error)
                return
            }
        }

    }
class RealmCacheHelper {
    func realm() throws -> Realm {
        return try Realm(configuration: config)
    }
}

Version of Realm and Tooling

Realm framework version: 10.1.4

Realm Object Server version: N/A

Xcode version: 12.2

iOS/OSX version: 10, 12, 13, 14

Dependency manager + version: CocoaPods 1.10.0

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 19 (5 by maintainers)

Most upvoted comments

Since the behaviour mentioned here (doing background work during the termination phase of an application) is not something we generally advise, I’m going to close this issue.

@KimiChiu I had the same issue on my side, which occurred 100% in background state. After disabling file protection for realm directory the crash disappeared.

        // Disable file protection for realm directory to prevent crashes like mutex:locked
        // Source: https://github.com/realm/realm-cocoa/issues/7112#issuecomment-778218878
        let folderPath = configuration.fileURL!.deletingLastPathComponent().path
        do {
            let attributes = try FileManager.default.attributesOfItem(atPath: folderPath)
            let protectionType = attributes[.protectionKey] as? FileProtectionType
            if protectionType != .some(FileProtectionType.none) {
                try FileManager.default.setAttributes([.protectionKey: FileProtectionType.none], ofItemAtPath: folderPath)
            }
        } catch {
            print("Unable to set protection attributes for realm folder: \(error)")
        }

       return configuration
}

I don’t use any in memory realm database. The memoryCache in the code snippet is just a simple dictionary.