realm-swift icon indicating copy to clipboard operation
realm-swift copied to clipboard

EXC_BAD_ACCESS in get_number_of_versions()

Open mmar001 opened this issue 2 years ago • 9 comments

How frequently does the bug occur?

Sometimes

Description

The App faces a EXC_BAD_ACCESS when it try to write an object.

Stacktrace & log output

0  Realm                          0x197158 realm::DB::get_number_of_versions() + 24
1  Realm                          0x450f18 check_can_create_write_transaction(realm::Realm const*) + 92
2  Realm                          0x451d60 realm::Realm::begin_transaction() + 56
3  Realm                          0x12bb24 -[RLMRealm beginWriteTransactionWithError:] + 24
4  RealmSwift                     0x6d524 $s10RealmSwift0A0V5write16withoutNotifying_xSaySo20RLMNotificationTokenCG_xyKXEtKlF + 140

Can you reproduce the bug?

Not yet

Reproduction Steps

No response

Version

10.28.0

What SDK flavour are you using?

Local Database only

Are you using encryption?

Yes

Platform OS and version(s)

iOS 15.4.1 ~ 15.6.1 - multiple iPhone

Build environment

Xcode version: Xcode 13.3

mmar001 avatar Aug 24 '22 17:08 mmar001

Hi @mmar001 can you give us more context on how you are using Realm? (code samples, if threading is used, if encryption is used etc.)

leemaguire avatar Aug 25 '22 10:08 leemaguire

saveOrUpdateToDb is the function that use db.write that cause the crash.

func updateToDb<T: Object>(_ object: T) {
        autoreleasepool {
            guard let db = getDatabase() else { return }

            do {
                try db.write {
                    db.create(T.self, value: object, update: .all)
                }
            } catch let error as NSError {
                logError(err: error)
            }
        }
    }

private func getDatabase() -> Realm? {
        return queue.sync {
            do {
                let db = try Realm(configuration: appConf)
                fixRealmBackgroundCrash(config: appConf)
                return db
            } catch {
                logError(err: error)

                let databaseConfiguration = Realm.Configuration(
                    schemaVersion: DatabaseManager.currentSchemaVersion,
                    migrationBlock: DatabaseManager.migrationBlock
                )
                let db = try? Realm(configuration: databaseConfiguration)
                fixRealmBackgroundCrash(config: databaseConfiguration)
          
                return db
            }
        }
    }

func fixRealmBackgroundCrash(config: Realm.Configuration) {
        // Source: https://github.com/realm/realm-cocoa/issues/7112#issuecomment-778218878
        let folderPath = config.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 {
            log("Unable to set protection attributes for realm folder: \(error)")
        }
    }

We use encryption and below is how we gat/create the db:

private var appConfiguration: Realm.Configuration

private init() {
        appConfiguration = getDatabaseConfiguration()
}

func getDatabaseConfiguration() -> Realm.Configuration{
        var databaseConfiguration = Realm.Configuration(
            schemaVersion: currentSchemaVersion,
            migrationBlock: DatabaseManager.migrationBlock,
            deleteRealmIfMigrationNeeded: false
        )
 
        databaseConfiguration.fileURL = getPath()
        let passphrase = getPassphrase()
       
        if let data = Data(base64Encoded: passphrase, options: NSData.Base64DecodingOptions()), data.count == 64 {
            databaseConfiguration.encryptionKey = data
        } else if let data = passphrase.data(using: .utf8), data.count == 64 {
            databaseConfiguration.encryptionKey = data
        } else {
            databaseConfiguration.encryptionKey = nil
        }

        return databaseConfiguration
    }

mmar001 avatar Aug 25 '22 11:08 mmar001

@mmar001 are you able to send us a sample app that can reproduce this issue?

leemaguire avatar Aug 26 '22 08:08 leemaguire

I cannot reproduce the issue. It is reported in Crashlytics and happens only to live user, not in debug . I see that in v10.28.5 there is a fix regarding the versioning, this could be related?

mmar001 avatar Aug 26 '22 09:08 mmar001

That fix is not related. We will require more full stacktraces to better understand what could be happening.

leemaguire avatar Aug 26 '22 11:08 leemaguire

Below the full stacktrace. Realm runs in multiple thread in the app.

0  Realm                          0x197158 realm::DB::get_number_of_versions() + 24
1  Realm                          0x450f18 check_can_create_write_transaction(realm::Realm const*) + 92
2  Realm                          0x451d60 realm::Realm::begin_transaction() + 56
3  Realm                          0x12bb24 -[RLMRealm beginWriteTransactionWithError:] + 24
4  RealmSwift                     0x6d524 $s10RealmSwift0A0V5write16withoutNotifying_xSaySo20RLMNotificationTokenCG_xyKXEtKlF + 140
…
8  libswiftObjectiveC.dylib       0x1a10 autoreleasepool<A>(invoking:) + 64
…
15 libdispatch.dylib              0x1e6c _dispatch_call_block_and_release + 32
16 libdispatch.dylib              0x3a30 _dispatch_client_callout + 20
17 libdispatch.dylib              0xb124 _dispatch_lane_serial_drain + 668
18 libdispatch.dylib              0xbc80 _dispatch_lane_invoke + 392
19 libdispatch.dylib              0x16500 _dispatch_workloop_worker_thread + 648
20 libsystem_pthread.dylib        0x10bc _pthread_wqthread + 288
21 libsystem_pthread.dylib        0xe5c start_wqthread + 8

com.apple.main-thread
0  libsystem_kernel.dylib         0x14a0 mach_msg_trap + 8
1  libsystem_kernel.dylib         0x1ae4 mach_msg + 76
2  CoreFoundation                 0x6d30 __CFRunLoopServiceMachPort + 372
3  CoreFoundation                 0xb1bc __CFRunLoopRun + 1180
4  CoreFoundation                 0x1ebc8 CFRunLoopRunSpecific + 600
5  GraphicsServices               0x1374 GSEventRunModal + 164
6  UIKitCore                      0x514b58 -[UIApplication _run] + 1100
7  UIKitCore                      0x296090 UIApplicationMain + 364
8  DE                             0x579148 main + 18 (AppDelegate.swift:18)
9  ???                            0x1054adda4 (Missing)

com.apple.uikit.eventfetch-thread
0  libsystem_kernel.dylib         0x14a0 mach_msg_trap + 8
1  libsystem_kernel.dylib         0x1ae4 mach_msg + 76
2  CoreFoundation                 0x6d30 __CFRunLoopServiceMachPort + 372
3  CoreFoundation                 0xb1bc __CFRunLoopRun + 1180
4  CoreFoundation                 0x1ebc8 CFRunLoopRunSpecific + 600
5  Foundation                     0x19444 -[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 236
6  Foundation                     0x5ae0c -[NSRunLoop(NSRunLoop) runUntilDate:] + 92
7  UIKitCore                      0x48ecc4 -[UIEventFetcher threadMain] + 524
8  Foundation                     0x6941c __NSThread__start__ + 808
9  libsystem_pthread.dylib        0x19ac _pthread_start + 148
10 libsystem_pthread.dylib        0xe68 thread_start + 8

queue.wifiDet
0  libsystem_kernel.dylib         0x4ba4 poll + 8
…
16 libdispatch.dylib              0x1e6c _dispatch_call_block_and_release + 32
17 libdispatch.dylib              0x3a30 _dispatch_client_callout + 20
18 libdispatch.dylib              0xb124 _dispatch_lane_serial_drain + 668
19 libdispatch.dylib              0xbc80 _dispatch_lane_invoke + 392
20 libdispatch.dylib              0x16500 _dispatch_workloop_worker_thread + 648
21 libsystem_pthread.dylib        0x10bc _pthread_wqthread + 288
22 libsystem_pthread.dylib        0xe5c start_wqthread + 8

queue.Network
0  libsystem_kernel.dylib         0x242c read + 8
…
27 libdispatch.dylib              0x1e6c _dispatch_call_block_and_release + 32
28 libdispatch.dylib              0x3a30 _dispatch_client_callout + 20
29 libdispatch.dylib              0xb124 _dispatch_lane_serial_drain + 668
30 libdispatch.dylib              0xbc80 _dispatch_lane_invoke + 392
31 libdispatch.dylib              0x16500 _dispatch_workloop_worker_thread + 648
32 libsystem_pthread.dylib        0x10bc _pthread_wqthread + 288
33 libsystem_pthread.dylib        0xe5c start_wqthread + 8

com.google.firebase.crashlytics.MachExceptionServer
0  FirebaseCrashlytics            0x1cf2c FIRCLSProcessRecordAllThreads + 184
1  FirebaseCrashlytics            0x1d30c FIRCLSProcessRecordAllThreads + 1176
2  FirebaseCrashlytics            0x1617c FIRCLSHandler + 48
3  FirebaseCrashlytics            0x18f44 FIRCLSMachExceptionServer + 1236
4  libsystem_pthread.dylib        0x19ac _pthread_start + 148
5  libsystem_pthread.dylib        0xe68 thread_start + 8

queue.devices
0  libsystem_kernel.dylib         0x4ba4 poll + 8
…
16 libdispatch.dylib              0x1e6c _dispatch_call_block_and_release + 32
17 libdispatch.dylib              0x3a30 _dispatch_client_callout + 20
18 libdispatch.dylib              0xb124 _dispatch_lane_serial_drain + 668
19 libdispatch.dylib              0xbc80 _dispatch_lane_invoke + 392
20 libdispatch.dylib              0x16500 _dispatch_workloop_worker_thread + 648
21 libsystem_pthread.dylib        0x10bc _pthread_wqthread + 288
22 libsystem_pthread.dylib        0xe5c start_wqthread + 8

com.apple.NSURLConnectionLoader
0  libsystem_kernel.dylib         0x14a0 mach_msg_trap + 8
1  libsystem_kernel.dylib         0x1ae4 mach_msg + 76
2  CoreFoundation                 0x6d30 __CFRunLoopServiceMachPort + 372
3  CoreFoundation                 0xb1bc __CFRunLoopRun + 1180
4  CoreFoundation                 0x1ebc8 CFRunLoopRunSpecific + 600
5  CFNetwork                      0x2781dc _CFURLStorageSessionDisableCache + 60032
6  Foundation                     0x6941c __NSThread__start__ + 808
7  libsystem_pthread.dylib        0x19ac _pthread_start + 148
8  libsystem_pthread.dylib        0xe68 thread_start + 8

Realm notification listener
0  libsystem_kernel.dylib         0x2e18 kevent + 8
1  Realm                          0x3aaf04 realm::_impl::ExternalCommitHelper::listen() + 156
2  Realm                          0x3ab054 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_delete<std::__1::__thread_struct> >, realm::_impl::ExternalCommitHelper::ExternalCommitHelper(realm::_impl::RealmCoordinator&)::$_0> >(void*) + 52
3  libsystem_pthread.dylib        0x19ac _pthread_start + 148
4  libsystem_pthread.dylib        0xe68 thread_start + 8

queue.provider
0  libsystem_kernel.dylib         0x242c read + 8
…
27 libdispatch.dylib              0x1e6c _dispatch_call_block_and_release + 32
28 libdispatch.dylib              0x3a30 _dispatch_client_callout + 20
29 libdispatch.dylib              0xb124 _dispatch_lane_serial_drain + 668
30 libdispatch.dylib              0xbc80 _dispatch_lane_invoke + 392
31 libdispatch.dylib              0x16500 _dispatch_workloop_worker_thread + 648
32 libsystem_pthread.dylib        0x10bc _pthread_wqthread + 288
33 libsystem_pthread.dylib        0xe5c start_wqthread + 8

Thread
0  libsystem_kernel.dylib         0x1a74 __workq_kernreturn + 8
1  libsystem_pthread.dylib        0x1108 _pthread_wqthread + 364
2  libsystem_pthread.dylib        0xe5c start_wqthread + 8

Thread
0  libsystem_kernel.dylib         0x1a74 __workq_kernreturn + 8
1  libsystem_pthread.dylib        0x1108 _pthread_wqthread + 364
2  libsystem_pthread.dylib        0xe5c start_wqthread + 8

Thread
0  libsystem_kernel.dylib         0x1a74 __workq_kernreturn + 8
1  libsystem_pthread.dylib        0x1108 _pthread_wqthread + 364
2  libsystem_pthread.dylib        0xe5c start_wqthread + 8```

mmar001 avatar Aug 26 '22 12:08 mmar001

For running Realm on different threads, you need to confine the Realm to a queue. Can you try something along the lines of:

func updateToDb<T: Object>(_ object: T, on queue: DispatchQueue) {
        queue.async {
            autoreleasepool {
                guard let db = getDatabase(on: queue) else { return }
                do {
                    try db.write {
                        db.create(T.self, value: object, update: .all)
                    }
                } catch let error as NSError {
                    logError(err: error)
                }
            }
        }
    }

private func getDatabase(on queue: DispatchQueue) -> Realm? {
            do {
                let db = try Realm(configuration: appConf, queue: queue)
                fixRealmBackgroundCrash(config: appConf) // This should only ever run once, I recommend moving it else where.
                return db
            } catch {
                logError(err: error)

                let databaseConfiguration = Realm.Configuration(
                    schemaVersion: DatabaseManager.currentSchemaVersion,
                    migrationBlock: DatabaseManager.migrationBlock
                )
                let db = try? Realm(configuration: databaseConfiguration, queue: queue)
                fixRealmBackgroundCrash(config: databaseConfiguration)
          
                return db
            }
    }

leemaguire avatar Aug 29 '22 10:08 leemaguire

@mmar001 did you take a look to the above comment?, I know there is no way to know this is fixed until you release a new version and you don't see the mentioned crash in your Crashlytics dashboard but it is really helpful to know if the issue continues or not.

dianaafanador3 avatar Sep 12 '22 09:09 dianaafanador3

Hello, yes we apply it but the crash is not fixed yet

mmar001 avatar Sep 13 '22 16:09 mmar001