realm-swift
realm-swift copied to clipboard
Multiple crashes with different stack traces ending up in `terminate` function
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