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

Multiple crashes with different stack traces ending up in `terminate` function

Open rserentill opened this issue 2 years ago • 0 comments

How frequently does the bug occur?

Sometimes

Description

We are seeing multiple crashes on production, although it is really hard for us to reproduce them.

We are accessing the database from different threads and concurrent threads might be writing to the database at the same time. However, we should always be on the same thread when creating and accessing realm. I will try to summarise what we are doing:

We have a class Repository which has a variable database:

class Repository<Model, RealmModel> {
  private var mainDatabaseThread: Thread!
  var mainDataBase : Realm?
  
  var database: Realm? {
    return Thread.current == mainDatabaseThread
      ? mainDataBase
      : try? Realm(configuration: configuration ?? .defaultConfiguration)
  }
  
  var configuration: RealmSwift.Realm.Configuration?
  
  init(database: Realm?, configuration: RealmSwift.Realm.Configuration?) {
    self.mainDatabaseThread = Thread.current
    self.mainDataBase = database
    self.configuration = configuration
  }

  ...

}

NOTE: configuration should never be nil, that would mean try Realm() threw an exception while creating Repository instance outside.

This class has some functions to create/retrieve/update/delete objects. Functions needing to write on the database do so like this:

try database?.safeWrite {
  database?.add(dbEntities, update: .all) // or any other operation
}

safeWrite is a custom extension we implemented, trying to mitigate crashes related to Realm already being in a write transaction:

extension Realm {
  func safeWrite<Result>(_ block: (() throws -> Result)) throws -> Result {
    guard !isInWriteTransaction else { return try block() }
    return try write(block)
  }
}

But we then also have other classes inheriting from Repository, let's say RepositoryA which also access database from its super class:

final class RepositoryA: Repository<Download, DownloadRealm> {
  func markAsCompleted(_ download: Download) throws {
    let predicate = NSPredicate(format: "id = %@", download.id)
    
    try database?.safeWrite {
      if let download = database?.objects(DownloadRealm.self).filter(predicate).first {
        download.completed = true
      }
    }
  }
}

Can this be something related with threading? should we always create a new Realm instance when accessing the database with try! Realm()?

Stacktrace & log output

Crashed: com.apple.main-thread
0  libsystem_kernel.dylib         0x7b38 __pthread_kill + 8
1  libsystem_pthread.dylib        0x73bc pthread_kill + 268
2  libsystem_c.dylib              0x20524 abort + 168
3  myapp                          0x9fedd4 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 128 (terminate.cpp:128)
4  myapp                          0x9ff114 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 123 (terminate.cpp:123)
5  myapp                          0x9fee90 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 133 (terminate.cpp:133)
6  myapp                          0x597208 void realm::util::terminate_with_info<char const&, unsigned long&>(char const*, int, char const*, char const*, char const&, unsigned long&) + 51 (terminate.hpp:51)
7  myapp                          0x7378c0 realm::Array::set_as_ref(unsigned long, unsigned long) + 389 (array.cpp:389)
8  myapp                          0x7d6050 realm::Obj& realm::Obj::set<bool>(realm::ColKey, bool, bool) + 159 (node.hpp:159)
9  myapp                          0x53caa4 void (anonymous namespace)::kvoSetValue<bool, bool>(RLMObjectBase*, unsigned long, bool) + 405 (RLMAccessor.mm:405)
10 myapp                          0x33976c closure #1 in IssueDownloadMetadataDatabaseRepositoryRealm.markAsCompleted(_:) + 260 (<compiler-generated>:260)

---

Crashed: com.apple.NSURLSession-delegate
0  libsystem_kernel.dylib         0x7b38 __pthread_kill + 8
1  libsystem_pthread.dylib        0x73bc pthread_kill + 268
2  libsystem_c.dylib              0x20524 abort + 168
3  myapp                          0x9fedd4 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 128 (terminate.cpp:128)
4  myapp                          0x9ff114 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 123 (terminate.cpp:123)
5  myapp                          0x9fee90 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 133 (terminate.cpp:133)
6  myapp                          0x5bcb50 std::__1::__vector_base<double, std::__1::allocator<double> >::__throw_length_error() const + 396 (vector:396)
7  myapp                          0x7d5a3c realm::Node::calc_item_count(unsigned long, unsigned long) const + 61 (node.cpp:61)
8  myapp                          0x7d5a90 realm::Node::alloc(unsigned long, unsigned long) + 76 (node.cpp:76)
9  myapp                          0x7376ac realm::Array::alloc(unsigned long, unsigned long) + 207 (array.hpp:207)
10 myapp                          0x737b74 realm::Array::insert(unsigned long, long long) + 447 (array.cpp:447)
11 myapp                          0x75a170 void realm::Cluster::do_insert_row<realm::ArrayInteger>(unsigned long, realm::ColKey, realm::Mixed, bool) + 275 (cluster.cpp:275)
12 myapp                          0x759f18 realm::util::FunctionRef<bool (realm::ColKey)>::FunctionRef<realm::Cluster::insert_row(unsigned long, realm::ObjKey, realm::FieldValues const&)::$_1&>(realm::Cluster::insert_row(unsigned long, realm::ObjKey, realm::FieldValues const&)::$_1&)::'lambda'(void*, realm::ColKey)::__invoke(void*, realm::ColKey) + 386 (cluster.cpp:386)
13 myapp                          0x9cb26c realm::TableClusterTree::for_each_and_every_column(realm::util::FunctionRef<bool (realm::ColKey)>) const + 68 (table.hpp:68)
14 myapp                          0x755044 realm::Cluster::insert_row(unsigned long, realm::ObjKey, realm::FieldValues const&) + 440 (cluster.cpp:440)
15 myapp                          0x756ce0 realm::Cluster::insert(realm::ObjKey, realm::FieldValues const&, realm::ClusterNode::State&) + 703 (cluster.cpp:703)
16 myapp                          0x765a18 realm::ClusterTree::insert_fast(realm::ObjKey, realm::FieldValues const&, realm::ClusterNode::State&) + 882 (cluster_tree.cpp:882)
17 myapp                          0x765b8c realm::ClusterTree::insert(realm::ObjKey, realm::FieldValues const&) + 900 (cluster_tree.cpp:900)
18 myapp                          0x9cae14 realm::TableClusterTree::insert(realm::ObjKey, realm::FieldValues const&) + 47 (table_cluster_tree.cpp:47)
19 myapp                          0x9bf8a8 realm::Table::create_object_with_primary_key(realm::Mixed const&, realm::FieldValues&&, realm::Table::UpdateMode, bool*) + 3067 (table.cpp:3067)
20 myapp                          0x54b95c realm::Table::create_object_with_primary_key(realm::Mixed const&, bool*) + 485 (vector:485)
21 myapp                          0x540dd4 realm::Object realm::Object::create<objc_object* __strong, RLMAccessorContext>(RLMAccessorContext&, std::__1::shared_ptr<realm::Realm> const&, realm::ObjectSchema const&, objc_object* __strong, realm::CreatePolicy, realm::ObjKey, realm::Obj*) + 305 (object_accessor.hpp:305)
22 myapp                          0x540774 RLMAccessorContext::createObject(objc_object*, realm::CreatePolicy, bool, realm::ObjKey) + 1102 (RLMAccessor.mm:1102)
23 myapp                          0x595d5c RLMAddObjectToRealm + 120 (RLMObjectStore.mm:120)
24 myapp                          0x33651c closure #1 in IssueDatabaseRepositoryRealm.createOrUpdate(_:) + 61 (IssueDatabaseRepositoryRealm.swift:61)
25 myapp                          0x340f58 thunk for @callee_guaranteed () -> (@error @owned Error) + 20 (<compiler-generated>:20)
26 myapp                          0x3388a4 partial apply for thunk for @callee_guaranteed () -> (@error @owned Error) + 16 (<compiler-generated>:16)
27 myapp                          0x6facc8 Realm.write<A>(withoutNotifying:_:) + 258 (Realm.swift:258)
28 myapp                          0x335c40 IssueDatabaseRepositoryRealm.createOrUpdate(_:) + 552 (<compiler-generated>:552)

---

Crashed: com.apple.NSURLSession-delegate
0  libsystem_kernel.dylib         0x7b38 __pthread_kill + 8
1  libsystem_pthread.dylib        0x73bc pthread_kill + 268
2  libsystem_c.dylib              0x20524 abort + 168
3  myapp                          0x7b0ab4 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 128 (terminate.cpp:128)
4  myapp                          0x7b0df4 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 123 (terminate.cpp:123)
5  myapp                          0x7b0b70 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 133 (terminate.cpp:133)
6  myapp                          0x5911d0 realm::StringData realm::Obj::_get<realm::StringData>(realm::ColKey::Idx) const + 156 (array_string_short.hpp:156)
7  myapp                          0x5926b0 realm::Obj::get_any(realm::ColKey) const + 395 (mixed.hpp:395)
8  myapp                          0x550d88 long long realm::IndexArray::index_string<(realm::IndexMethod)0>(realm::Mixed, realm::InternalFindResult&, realm::ClusterColumn const&) const + 215 (mixed.hpp:215)
9  myapp                          0x5507d4 realm::IndexArray::index_string_find_first(realm::Mixed, realm::ClusterColumn const&) const + 585 (index_string.cpp:585)
10 myapp                          0x76f400 realm::ObjKey realm::Table::find_first<realm::StringData>(realm::ColKey, realm::StringData) const + 464 (index_string.hpp:464)
11 myapp                          0x6d6340 realm::StringNode<realm::Equal>::_search_index_init() + 346 (query_engine.cpp:346)
12 myapp                          0x6a8c04 realm::Query::init() const + 459 (vector:459)
13 myapp                          0x6a8c8c realm::Query::do_find_all(realm::TableView&, unsigned long) const + 680 (vector:680)
14 myapp                          0x782c0c realm::TableView::do_sync() + 603 (table_view.cpp:603)
15 myapp                          0x6a8f80 realm::Query::find_all(unsigned long) + 1528 (query.cpp:1528)
16 myapp                          0x5f5338 realm::Results::ensure_up_to_date(realm::Results::EvaluateMode) + 275 (results.cpp:275)
17 myapp                          0x5f4d50 realm::util::Optional<realm::Obj> realm::Results::try_get<realm::Obj>(unsigned long) + 368 (results.cpp:368)
18 myapp                          0x5f5058 realm::util::Optional<realm::Obj> realm::Results::first<realm::Obj>() + 139 (__mutex_base:139)
19 myapp                          0x423a3c RLMAccessorContext realm::Results::dispatch<auto realm::Results::first<RLMAccessorContext>(RLMAccessorContext&)::'lambda'(RLMAccessorContext&)>(RLMAccessorContext&) const + 404 (optional.hpp:404)
20 myapp                          0x42388c auto realm::Results::first<RLMAccessorContext>(RLMAccessorContext&) + 420 (results.hpp:420)
21 myapp                          0x421668 -[RLMResults firstObject] + 248 (RLMResults.mm:248)
22 myapp                          0x47c7cc RealmCollectionImpl.first.getter + 72
23 myapp                          0x47fa74 protocol witness for RealmCollection.first.getter in conformance Results<A> + 80 (<compiler-generated>:80)
24 myapp                          0x81b69c IssueDatabaseRepositoryRealm.createOrUpdate(_:) + 27 (IssueDatabaseRepositoryRealm.swift:27)

---

Crashed: com.apple.main-thread
0  libsystem_kernel.dylib         0x7b38 __pthread_kill + 8
1  libsystem_pthread.dylib        0x73bc pthread_kill + 268
2  libsystem_c.dylib              0x20524 abort + 168
3  myapp                          0x9fedd4 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 128 (terminate.cpp:128)
4  myapp                          0x9ff114 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 123 (terminate.cpp:123)
5  myapp                          0x9fee90 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 133 (terminate.cpp:133)
6  myapp                          0x76dea8 realm::DB::do_end_write() + 2291 (db.cpp:2291)
7  myapp                          0x77026c realm::Transaction::rollback() + 2790 (db.cpp:2790)
8  myapp                          0x76cd18 realm::Transaction::close() + 2693 (db.cpp:2693)
9  myapp                          0x777c00 std::__1::__shared_ptr_pointer<realm::Transaction*, (anonymous namespace)::$_8, std::__1::allocator<realm::Transaction> >::__on_zero_shared() + 393 (db.cpp:393)
10 myapp                          0x54f3c8 std::__1::shared_ptr<realm::app::App>::~shared_ptr() + 220 (shared_ptr.h:220)
11 myapp                          0x887238 realm::Realm::~Realm() + 104 (shared_realm.cpp:104)
12 myapp                          0x54f3c8 std::__1::shared_ptr<realm::app::App>::~shared_ptr() + 220 (shared_ptr.h:220)
13 libobjc.A.dylib                0x8380 object_cxxDestructFromClass(objc_object*, objc_class*) + 116
14 libobjc.A.dylib                0x51b4 objc_destructInstance + 80
15 libobjc.A.dylib                0xea00 _objc_rootDealloc + 80
16 myapp                          0x65ebe4 -[RLMRealm dealloc] + 941 (RLMRealm.mm:941)
17 libobjc.A.dylib                0x7b14 AutoreleasePoolPage::releaseUntil(objc_object**) + 196
18 libobjc.A.dylib                0x3e54 objc_autoreleasePoolPop + 212
19 CoreFoundation                 0x13dd4 _CFAutoreleasePoolPop + 32
20 CoreFoundation                 0xcaf4 __CFRunLoopPerCalloutARPEnd + 48
21 CoreFoundation                 0xb748 __CFRunLoopRun + 2600
22 CoreFoundation                 0x1ebc8 CFRunLoopRunSpecific + 600
23 GraphicsServices               0x1374 GSEventRunModal + 164
24 UIKitCore                      0x514b58 -[UIApplication _run] + 1100
25 UIKitCore                      0x296098 UIApplicationMain + 364
26 myapp                          0x7418 main + 164 (<compiler-generated>:164)
27 ???                            0x107d61da4 (Missing)

---

Crashed: com.apple.main-thread
0  libsystem_kernel.dylib         0x6bbc __pthread_kill + 8
1  libsystem_pthread.dylib        0xd854 pthread_kill + 208
2  libsystem_c.dylib              0x1f6ac abort + 124
3  myapp                          0x7b0ab4 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 128 (terminate.cpp:128)
4  myapp                          0x7b0df4 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 123 (terminate.cpp:123)
5  myapp                          0x7b0b70 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 133 (terminate.cpp:133)
6  myapp                          0x4f35e8 realm::Array::get(char const*, unsigned long) + 1355 (array.cpp:1355)
7  myapp                          0x6d59e4 realm::ParentNode::aggregate_local(realm::QueryStateBase*, unsigned long, unsigned long, unsigned long, realm::ArrayPayload*) + 119 (query_engine.cpp:119)
8  myapp                          0x6a67f4 realm::Query::aggregate_internal(realm::ParentNode*, realm::QueryStateBase*, unsigned long, unsigned long, realm::ArrayPayload*) const + 1041 (query.cpp:1041)
9  myapp                          0x6ac3f8 realm::util::FunctionRef<bool (realm::Cluster const*)>::FunctionRef<realm::Query::do_count(unsigned long) const::$_4&>(realm::Query::do_count(unsigned long) const::$_4&)::'lambda'(void*, realm::Cluster const*)::__invoke(void*, realm::Cluster const*) + 1596 (query.cpp:1596)
10 myapp                          0x51d830 realm::ClusterNodeInner::traverse(realm::util::FunctionRef<bool (realm::Cluster const*)>, long long) const + 416 (cluster_tree.cpp:416)
11 myapp                          0x51ee30 realm::ClusterTree::traverse(realm::util::FunctionRef<bool (realm::Cluster const*)>) const + 1002 (cluster_tree.cpp:1002)
12 myapp                          0x6a91b8 realm::Query::do_count(unsigned long) const + 93 (query_state.hpp:93)
13 myapp                          0x6a942c realm::Query::count(realm::DescriptorOrdering const&) + 1664 (query.cpp:1664)
14 myapp                          0x5fc010 realm::Results::size() + 136 (results.cpp:136)
15 myapp                          0x42101c -[RLMResults count] + 148 (RLMResults.mm:148)
16 myapp                          0x47c6c0 RealmCollectionImpl.count.getter + 37 (RealmCollectionImpl.swift:37)
17 myapp                          0x81fea8 IssueDownloadMetadataDatabaseRepositoryRealm.countPendingDownloads(_:) + 114 (IssueDownloadMetadataDatabaseRepositoryRealm.swift:114)

Can you reproduce the bug?

Not yet

Reproduction Steps

We think the crashes might occur while doing a lot of write operations at once, but we were unable to fins a pattern.

Version

10.28.0

What SDK flavour are you using?

Local Database only

Are you using encryption?

No, not using encryption

Platform OS and version(s)

All different OS versions, not liked to a specific one

Build environment

Xcode version: 13.4.1 and 14.0 Dependency manager: SPM

rserentill avatar Sep 21 '22 08:09 rserentill