realm / realm-swift

Realm is a mobile database: a replacement for Core Data & SQLite
https://realm.io
Apache License 2.0
16.32k stars 2.15k forks source link

App randomly crashes after List modification #6832

Closed RustamG closed 4 years ago

RustamG commented 4 years ago

!!! MANDATORY TO FILL OUT !!!

Goals

App doesn't crash

Expected Results

App doesn't crash

Actual Results

App randomly crashes after modification of a List property Stack trace:

#0  0x000000010b2acadd in realm::util::EncryptedFileMapping::read_barrier(void const*, unsigned long, unsigned long (*)(char const*)) ()
#1  0x000000010acaed80 in realm::util::do_encryption_read_barrier(void const*, unsigned long, unsigned long (*)(char const*), realm::util::EncryptedFileMapping*) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/include/core/realm/util/file_mapper.hpp:133
#2  0x000000010b23ad8c in long long realm::ConstObj::_get<long long>(realm::ColKey::Idx) const ()
#3  0x000000010b201d64 in realm::ConstLstBase::get_child_ref(unsigned long) const ()
#4  0x000000010acb0075 in realm::BPlusTreeBase::init_from_parent() at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/include/core/realm/bplustree.hpp:175
#5  0x000000010b20892d in realm::Lst<realm::ObjKey>::Lst(realm::Obj const&, realm::ColKey) ()
#6  0x000000010b209c30 in realm::LnkLst::LnkLst(realm::Obj const&, realm::ColKey) ()
#7  0x000000010b201a2b in realm::Obj::get_listbase_ptr(realm::ColKey) const ()
#8  0x000000010acd5508 in realm::List::List(std::__1::shared_ptr<realm::Realm>, realm::Obj const&, realm::ColKey) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/ObjectStore/src/list.cpp:58
#9  0x000000010acd56b5 in realm::List::List(std::__1::shared_ptr<realm::Realm>, realm::Obj const&, realm::ColKey) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/ObjectStore/src/list.cpp:59
#10 0x000000010ae0b01e in -[RLMManagedArray initWithParent:property:] at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMManagedArray.mm:88
#11 0x000000010ae3435e in RLMInitializeSwiftAccessorGenerics at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMObjectStore.mm:105
#12 0x000000010ae3776e in RLMCreateObjectAccessor(RLMClassInfo&, realm::Obj&&) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMObjectStore.mm:276
#13 0x000000010add2114 in RLMAccessorContext::box(realm::Obj&&) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMAccessor.mm:662
#14 0x000000010adfaf06 in _ZZN5realm7Results3getI18RLMAccessorContextEEDaRT_mENKUlTyS4_E_clIPNS_3ObjEEES3_S4_ at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/include/results.hpp:336
#15 0x000000010adfab20 in _ZN5realmL14switch_on_typeINS_3ObjEZNS_7Results3getI18RLMAccessorContextEEDaRT_mEUlTyS6_E_EES5_NS_12PropertyTypeEOT0_ at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/include/property.hpp:189
#16 0x000000010adfa693 in _ZNK5realm7Results8dispatchIZNS0_3getI18RLMAccessorContextEEDaRT_mEUlTyS5_E_EES4_OS5_ at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/include/results.hpp:330
#17 0x000000010adf50a8 in auto realm::Results::get<RLMAccessorContext>(RLMAccessorContext&, unsigned long) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/include/results.hpp:336
#18 0x000000010adf4e8d in -[RLMFastEnumerator countByEnumeratingWithState:count:] at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMCollection.mm:127
#19 0x000000010adf527f in RLMFastEnumerate(NSFastEnumerationState*, unsigned long, id<RLMFastEnumerable>) at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMCollection.mm:165
#20 0x000000010ae0b7b0 in -[RLMManagedArray countByEnumeratingWithState:objects:count:] at /Users/rustamg/Documents/xCode/project-ios/project/Pods/Realm/Realm/RLMManagedArray.mm:247
#21 0x00007fff51c46b2c in NSFastEnumerationIterator.next() ()
#22 0x000000010c40e31d in RLMIterator.next() at /Users/rustamg/Documents/xCode/project-ios/project/Pods/RealmSwift/RealmSwift/RealmCollection.swift:34
#23 0x000000010c40e9e9 in protocol witness for IteratorProtocol.next() in conformance RLMIterator<A> ()
#24 0x00007fff51750395 in EnumeratedSequence.Iterator.next() ()
#25 0x0000000108d93591 in NavigateFlightRouteView.ViewModel.update(from:log:selection:) at /Users/rustamg/Documents/xCode/project-ios/project/project/UI/Navigate/Sidebar/Route/NavigateFlightRouteViewModel.swift:58
#26 0x0000000108d93257 in closure #2 in NavigateFlightRouteView.ViewModel.observeSource() at /Users/rustamg/Documents/xCode/project-ios/project/project/UI/Navigate/Sidebar/Route/NavigateFlightRouteViewModel.swift:48
#27 0x0000000108d932ac in thunk for @escaping @callee_guaranteed (@guaranteed Flight, @guaranteed FlightLog, @guaranteed NavigateFlightRouteView.ViewModel.ListItem.Selection?) -> () ()
#28 0x00007fff23510051 in Subscribers.Sink.receive(_:) ()
#29 0x00007fff23510260 in protocol witness for Subscriber.receive(_:) in conformance Subscribers.Sink<A, B> ()
#30 0x00007fff235ad641 in Publishers.FlatMap.Outer.receiveInner(_:_:) ()
#31 0x00007fff235ad544 in Publishers.FlatMap.Outer.Side.receive(_:) ()
#32 0x00007fff23521a70 in AbstractCombineLatest.receive(_:index:) ()
#33 0x00007fff23520f99 in AbstractCombineLatest.Side.receive(_:) ()
#34 0x00007fff23521036 in protocol witness for Subscriber.receive(_:) in conformance AbstractCombineLatest<A, B, C>.Side<A1> ()
#35 0x00007fff23500675 in FilterProducer.receive(_:) ()

Steps for others to Reproduce

The app launched just fine and the data loaded in UI properly, however when I added a newly created object to a List of object with one type (FlightLog), I had crash enumerating the List on the another object type (Flight). I combine the data from multiple objects using Combine so when FlightLog.cancelledCargo is modified I also access Flight.dropZones to update UI. I started to constantly experience crashes on Friday when invoking Flight.dropZones.enumerated(). I changed my code a little to try using subscripts and the app started to crash on Flight.dropZones.firstIndex(where:) instead.

After spending a few hours today (on Monday) I couldn't replicate the issue in a separate project despite using the exact same schema, Realm file, environment (iOS simulator) and the same code related to crash. I re-checked the scenario on the actual app and it doesn't crash anymore however the source code didn't change.

Code Sample

Realm configuration:

Realm.Configuration.defaultConfiguration = Realm.Configuration(schemaVersion: 18, migrationBlock: MigrateRealm.migrate)

Objects definition:

class Flight: Object {

    @objc dynamic var uuid: String = UUID().uuidString
    @objc dynamic var date: Date!
    @objc dynamic var color: Int = 0
    @objc dynamic var aircraft: FlightAircraft!
    @objc dynamic var chs: FlightCHS!
    @objc dynamic var takeoffZone: FlightAirstrip?
    @objc dynamic var landingZone: FlightAirstrip?
    let dropZones = List<FlightDropZone>()

    @objc dynamic var statusString = ""
    var status: Status {
        get {
            return Status(rawValue: statusString) ?? Status.draft
        }
        set {
            statusString = newValue.rawValue
        }
    }

    override class func primaryKey() -> String? {

        return Keys.uuid
    }

    enum Keys {
        static let uuid = "uuid"
        static let date = "date"
        static let chs = "chs"
        static let aircraft = "aircraft"
        static let dropZones = "dropZones"
    }

    enum Status: String {
        case draft
        case planned
        case complete
    }
}

class FlightLog: Object {

    @objc dynamic var flightUuid: String = ""
    @objc dynamic var startTime: Date = Date()
    @objc dynamic var finishTime: Date?

    let passes = List<ActualPass>()
    let cancelledCargo = List<CancelledCargo>()

    override class func primaryKey() -> String? {

        return Keys.flightUuid
    }

    var isFinished: Bool {

        finishTime != nil
    }

    enum Keys {

        static let flightUuid = "flightUuid"
    }
}

class CancelledCargo: Object {

    @objc dynamic var uuid: String = ""
    @objc dynamic var reason: String = ""

    override class func primaryKey() -> String? {

        Keys.uuid
    }
}

Crash place:

for (index, zone) in flight.dropZones.enumerated() { // <-- crashed here
// ...
}

Modification that triggered the crash:

            try realm.write {
                if !log.cancelledCargo.contains(where: { $0.uuid == cargoId }) {
                    cancellation.reason = reason
                    log.cancelledCargo.append(cancellation)
                }
            }

However I'm unable to reproduce the crash in a sample project, I can email it so you get better idea having more code around the crash.

It worth noting that the modification happens on the same thread as the data observation. The issue may be related to https://github.com/realm/realm-cocoa/issues/4204.

Version of Realm and Tooling

Realm framework version: I got the crash on 5.2.0 version of Realm. Then I updated to 5.4.7 and had the same crash.

Realm Object Server version: not relevant

Xcode version: 11.7

iOS/OSX version: iOS 13.7 iPad Air 3 Simulator

Dependency manager + version: CocoaPods 1.9.3

RustamG commented 4 years ago

Just caught this crash a couple of times again. Not sure if that's the cause. I used Realm Studio to remove the "CancelledCargo" objects. Then added one through my app UI using the code above. Will try to experiment with Realm Studio to figure out the constant steps to reproduce.

RustamG commented 4 years ago

So here are the steps. Looks like it really depends on the Realm Studio being opened (I have version 3.11.0).

  1. Launch my app
  2. Add object1 to a List programmatically
  3. Open Realm Studio
  4. Delete object1 using Realm Studio
  5. Add object2 to a List programmatically
  6. Remove object2 programmatically. // Doesn't crash so far
  7. Re-launch the app having Realm Studio open
  8. Add object3 to a List programmatically The app crashes!
pavel-ship-it commented 4 years ago

Hi @RustamG , Thank you for the detailed description. Realm Studio could lead app to crash because of new locking mechanism. Here is the similar crash #6752 Is it happened on Simulator only? Is it happened when you're running the app without Realm Studio connected? Could you please try to update Realm to the latest version?

RustamG commented 4 years ago

Thanks for quick response @pavel-ship-it

Is it happened on Simulator only?

I tested it only on Simulator. Haven't observed such crash on the device.

Is it happened when you're running the app without Realm Studio connected?

No

Could you please try to update Realm to the latest version?

I'm on v5.4.7 which is the latest as of now.

pavel-ship-it commented 4 years ago

Hey @RustamG, thanks for the update.

This issue will be fixed in the new release of Realm Studio. As a workaround you should avoid using same realm in Realm Studio and in the app simultaneously.

I'll close this ticket. If the you still see the same issue in a new version please comment and we can re-open it.