realm-swift
realm-swift copied to clipboard
Crash when adding object to realm
How frequently does the bug occur?
Sometimes
Description
Realm seems to crash for some users when adding new objects to realm
I have seen similar issues since 10.22.0, but this is also happening since the 10.24.0 upgrade.
Stacktrace & log output
Crashed: com.apple.main-thread
SIGABRT ABORT 0x00000001b8563964
shell
Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x28414 __pthread_kill + 8
1 libsystem_pthread.dylib 0x2b40 pthread_kill + 272
2 libsystem_c.dylib 0x76b74 abort + 104
3 MyApp 0x6806d8 std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_stringstream() + 821 (sstream:821)
4 MyApp 0x6808dc realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 123 (terminate.cpp:123)
5 MyApp 0x680a14 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 140 (terminate.cpp:140)
6 MyApp 0x358284 realm::BPlusTree<double>::get_uncached(unsigned long) const + 371 (bplustree.hpp:371)
7 MyApp 0x4b60f0 realm::Node::calc_item_count(unsigned long, unsigned long) const + 61 (node.cpp:61)
8 MyApp 0x4b6144 realm::Node::alloc(unsigned long, unsigned long) + 76 (node.cpp:76)
9 MyApp 0x42e52c realm::Array::alloc(unsigned long, unsigned long) + 207 (array.hpp:207)
10 MyApp 0x42e9e8 realm::Array::insert(unsigned long, long long) + 447 (array.cpp:447)
11 MyApp 0x44124c realm::ArrayTimestamp::insert(unsigned long, realm::Timestamp) + 70 (array_timestamp.cpp:70)
12 MyApp 0x44d860 void realm::Cluster::do_insert_row<realm::ArrayTimestamp>(unsigned long, realm::ColKey, realm::Mixed, bool) + 28 (array_timestamp.hpp:28)
13 MyApp 0x44c9dc realm::util::FunctionRef<bool (realm::ColKey)>::FunctionRef<realm::Cluster::insert_row(unsigned long, realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&)::$_1&>(realm::Cluster::insert_row(unsigned long, realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&)::$_1&)::'lambda'(void*, realm::ColKey)::__invoke(void*, realm::ColKey) + 378 (cluster.cpp:378)
14 MyApp 0x6551dc realm::TableClusterTree::for_each_and_every_column(realm::util::FunctionRef<bool (realm::ColKey)>) const + 119 (function_ref.hpp:119)
15 MyApp 0x4482e4 realm::Cluster::insert_row(unsigned long, realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&) + 409 (cluster.cpp:409)
16 MyApp 0x449f38 realm::Cluster::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&) + 672 (cluster.cpp:672)
17 MyApp 0x456d24 realm::ClusterTree::insert_fast(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&) + 882 (cluster_tree.cpp:882)
18 MyApp 0x456ec0 realm::ClusterTree::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&) + 906 (cluster_tree.cpp:906)
19 MyApp 0x654f7c realm::TableClusterTree::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&) + 47 (table_cluster_tree.cpp:47)
20 MyApp 0x64adf8 realm::Table::create_object_with_primary_key(realm::Mixed const&, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> >&&, bool*) + 3010 (table.cpp:3010)
21 MyApp 0x2f3de8 realm::Table::create_object_with_primary_key(realm::Mixed const&, bool*) + 463 (vector:463)
22 MyApp 0x2e924c 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*) + 298 (object_accessor.hpp:298)
23 MyApp 0x2e8c70 RLMAccessorContext::createObject(objc_object*, realm::CreatePolicy, bool, realm::ObjKey) + 1093 (RLMAccessor.mm:1093)
24 MyApp 0x330774 RLMAddObjectToRealm + 139 (RLMObjectStore.mm:139)
25 MyApp 0x75150 thunk for @callee_guaranteed () -> (@error @owned Error) + 4343763280 (<compiler-generated>:4343763280)
26 MyApp 0x24c788 partial apply for thunk for @callee_guaranteed () -> (@error @owned Error) + 4345694088 (<compiler-generated>:4345694088)
27 MyApp 0x24d6b4 thunk for @callee_guaranteed () -> (@error @owned Error)partial apply + 4345697972
28 MyApp 0x75a0a4 Realm.write<A>(withoutNotifying:_:) + 255 (Realm.swift:255)
Can you reproduce the bug?
Not yet
Reproduction Steps
No response
Version
10.24.0
What SDK flavour are you using?
Local Database only
Are you using encryption?
No, not using encryption
Platform OS and version(s)
iOS 15
Build environment
Xcode version: 13.2.1 Dependency manager and version: SPM
Hi @sipersso Do you have any code which may help to reproduce the issue?
It only happens very infrequently in production and I have not been able to reproduce it locally I am afraid :/
I noticed that the actual crash was missing from firebase so I added that: Not sure if it helps:
Crashed: com.apple.main-thread SIGABRT ABORT 0x00000001b8563964.
Hi @sipersso
- Do you know what the size of the Realm file is when the crash occurs?
- Do you have any analytics for how long the app is running before a crash happens?
- Are you keeping references of Realm objects/results/realms alive anywhere in your app?
1: I don't know the size of the realm file, but this is maybe something that I could add tracking for in a future update.
2: I don't. But I can see that there are repetitive crashes. The affected have crashes within minutes of each other.
3: I don't have any global realm instances if that is what you are talking about. I wrap all calls to realm in background threads in autoreleasepools.
I did see another realm thread in crashlytics if that helps in Realm notification listener. external_commit_helper.cpp - Line 221 realm::_impl::ExternalCommitHelper::listen() + 221 tuple - Line 181 void* std::__1::__thread_proxy<std::__1::tuple<std::__1::unique_ptr<std::__1::__thread_struct, std::__1::default_deletestd::__1::__thread_struct >, realm::_impl::ExternalCommitHelper::ExternalCommitHelper(realm::_impl::RealmCoordinator&)::$_0> >(void*) + 181
@sipersso could you show us how you wrap the calls the background threads in autorelease pools?
The actual call that failed is done on the main thread and does not contain any autoreleasepools. It is not a simple proof of concept app, but an example is this:
DispatchQueue.global().async { [weak self] in
guard let self = self else {
return
}
autoreleasepool{
try! Realm()
//do something on the background thread
}
}
I assume I could in some cases avoid the try! and replace it with error handling instead of crashing. Do you think it is the try! Realm() that causes the crashes?
Is there anything in particular you are looking for here?
Realms are not supported on concurrent queues, which is what global()
is. You should create a serial queue to use a Realm on a non main thread. e.g.
let queue = DispatchQueue(label: "my-queue")
queue.async {
let realm = try! Realm(configuration: .defaultConfiguration, queue: queue)
}
Would you be able to remove the usage of Realms with concurrent queues and see if that solves the issue?
Realms are not supported on concurrent queues, which is what
global()
is. You should create a serial queue to use a Realm on a non main thread. e.g.let queue = DispatchQueue(label: "my-queue") queue.async { let realm = try! Realm(configuration: .defaultConfiguration, queue: queue) }
Would you be able to remove the usage of Realms with concurrent queues and see if that solves the issue?
Yes, I can definitely remove the use of global(). I'll try this out. Thanks!
By the way @leemaguire maybe this is something that should be made a little more clear in the documentation? I just read https://docs.mongodb.com/realm/sdk/swift/advanced-guides/threading/ and there is no mention there that you should avoid concurrent queues and DispatchQueue.global() and when searching on GitHub I see that you have written the same response to many open issues. Maybe something to add to the docs?
@leemaguire FIY... I have changed all background operations to use serial queues as per your recommendation. But the issue still persists.
The write operation in this case is performed on the main thread. Could that have anything to do with it? I am in the process of switching to writing on background threads, but not done with that yet. I am not using sync, only local realms for now.
@sipersso once you read / write from the realm on the queue that it is bound to things should be fine. Do you have any additional crash logs and any new code snippets you could share with us?
I think all of the issues here are caused by corrupted realms. The corruption seems to have happened for 10.22.0, but I don't see many new instances of these after upgrading. However, if there is corrupt data in the realm, upgrading won't help. You have to delete and reinstall the app (and thus risk loosing data, since I haven't been able to migrate to MongoDb Realm yet). Realm doesn't offer any API for detecting corruption in local files so all I can do is to wait for the user to reach out after getting multiple repeated crashes :/
I have an open support case: 00900582 and have shared more info there. (Including a realm file with corrupted data)
Just chiming in to say that this keeps constantly happening for us also to a very large number of users with tens of thousands of crashes per day. It would be nice if this could be investigated with a high priority if at all possible! The situation is bad enough to have us start thinking about a migration strategy away from using Realm entirely in our product.
We are also writing everything in main queue and the storage engine has been unstable before, but after the v10.20.2 update(s) it seems to have taken a significant turn for the worse. Currently we are using v10.24.1 and it's still experiencing these issues.
@anlaital are you using sync? or just locally? To be fair, I think the crashes for me has been limited to t a few people on the 10.22.0 update. But I haven't seen many crashes for other users after that. The app does have quite a lot of volume with 100k+ active users.
If you got repeated crashes even before the 10.22.0 update, maybe there is something wrong with your Realm usage? Tens of thousands of crashes per day sounds a lot though. Sorry you have to go through this.
@anlaital do you see the same stack trace as I do?
We are not using sync at all.
Realm storage engine has always been somewhat volatile, but with the most recent updates it's just gone to a whole new level of pain. I don't think there is anything we are doing wrong, it's just that our data volumes are large as is our user base and our models are fairly complex and see heavy usage throughout the application.
Here's a stack trace where simply deleting an object from the Realm causes constant crashes:
Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x69e8 __pthread_kill + 8
1 libsystem_pthread.dylib 0x10824 pthread_kill + 208
2 libsystem_c.dylib 0x1f0b4 abort + 120
3 Realm 0x2cb940 realm::util::terminate(char const*, char const*, long) + 10
4 Realm 0x2cbc40 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 328
5 Realm 0x2cbdb8 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 328
6 Realm 0x159368 realm::ArrayBacklink::remove(unsigned long, realm::ObjKey) + 460
7 Realm 0x20049c realm::Obj::remove_one_backlink(realm::ColKey, realm::ObjKey) + 312
8 Realm 0x1721f0 realm::Cluster::remove_backlinks(realm::ObjKey, realm::ColKey, std::__1::vector<realm::ObjKey, std::__1::allocator<realm::ObjKey> > const&, realm::CascadeState&) const + 356
9 Realm 0x177f94 realm::Cluster::do_erase_key(unsigned long, realm::ColKey, realm::CascadeState&) + 284
10 Realm 0x177150 realm::util::FunctionRef<bool (realm::ColKey)>::FunctionRef<realm::Cluster::erase(realm::ObjKey, realm::CascadeState&)::$_3&>(realm::Cluster::erase(realm::ObjKey, realm::CascadeState&)::$_3&)::'lambda'(void*, realm::ColKey)::__invoke(void*, realm::ColKey) + 2164
11 Realm 0x2a1e5c realm::TableClusterTree::for_each_and_every_column(realm::util::FunctionRef<bool (realm::ColKey)>) const + 84
12 Realm 0x171430 realm::Cluster::erase(realm::ObjKey, realm::CascadeState&) + 160
13 Realm 0x17f69c realm::ClusterNodeInner::erase(realm::ObjKey, realm::CascadeState&)::$_3::operator()(realm::ClusterNode*, realm::ClusterNodeInner::ChildInfo&) const + 68
14 Realm 0x17b3d4 realm::ClusterNodeInner::erase(realm::ObjKey, realm::CascadeState&) + 240
15 Realm 0x17e238 realm::ClusterTree::erase(realm::ObjKey, realm::CascadeState&) + 128
16 Realm 0x2962ac realm::Table::remove_object(realm::ObjKey) + 268
17 Realm 0x1f8fa8 realm::Obj::remove() + 44
18 Realm 0x5a89c RLMDeleteObjectFromRealm + 190 (RLMObjectStore.mm:190)
Here's one where simply adding an object to Realm causes it to blow up constantly:
Crashed: com.apple.main-thread
0 libsystem_kernel.dylib 0x7b78 __pthread_kill + 8
1 libsystem_pthread.dylib 0x73bc pthread_kill + 268
2 libsystem_c.dylib 0x2051c abort + 168
3 Realm 0x2cb940 realm::util::terminate(char const*, char const*, long) + 10
4 Realm 0x2cbc40 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 328
5 Realm 0x2cbdb8 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 328
6 Realm 0x5b858 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 Realm 0x175008 realm::util::FunctionRef<bool (realm::ColKey)>::FunctionRef<realm::Cluster::move(unsigned long, realm::ClusterNode*, long long)::$_2&>(realm::Cluster::move(unsigned long, realm::ClusterNode*, long long)::$_2&)::'lambda'(void*, realm::ColKey)::__invoke(void*, realm::ColKey) + 322
8 Realm 0x173cac void realm::Cluster::do_insert_row<realm::BasicArrayNull<double> >(unsigned long, realm::ColKey, realm::Mixed, bool) + 208
9 Realm 0x173494 realm::util::FunctionRef<bool (realm::ColKey)>::FunctionRef<realm::Cluster::insert_row(unsigned long, realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&)::$_1&>(realm::Cluster::insert_row(unsigned long, realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&)::$_1&)::'lambda'(void*, realm::ColKey)::__invoke(void*, realm::ColKey) + 612
10 Realm 0x2a1e5c realm::TableClusterTree::for_each_and_every_column(realm::util::FunctionRef<bool (realm::ColKey)>) const + 84
11 Realm 0x16ef20 realm::Cluster::insert_row(unsigned long, realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&) + 212
12 Realm 0x170f4c realm::Cluster::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&) + 240
13 Realm 0x17f308 realm::ClusterNodeInner::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&)::$_1::operator()(realm::ClusterNode*, realm::ClusterNodeInner::ChildInfo&) const + 72
14 Realm 0x17a3f0 realm::ClusterNodeInner::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&) + 248
15 Realm 0x17f308 realm::ClusterNodeInner::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&)::$_1::operator()(realm::ClusterNode*, realm::ClusterNodeInner::ChildInfo&) const + 72
16 Realm 0x17a4a4 realm::ClusterNodeInner::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&) + 428
17 Realm 0x17dcb0 realm::ClusterTree::insert_fast(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&, realm::ClusterNode::State&) + 48
18 Realm 0x17df90 realm::ClusterTree::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&) + 164
19 Realm 0x2a1990 realm::TableClusterTree::insert(realm::ObjKey, std::__1::vector<realm::FieldValue, std::__1::allocator<realm::FieldValue> > const&) + 52
20 Realm 0xc51c 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*) + 322 (object_accessor.hpp:322)
21 Realm 0xbbe4 RLMAccessorContext::createObject(objc_object*, realm::CreatePolicy, bool, realm::ObjKey) + 1093 (RLMAccessor.mm:1093)
22 Realm 0x5a2f4 RLMAddObjectToRealm + 139 (RLMObjectStore.mm:139)
23 RealmSwift 0x69774 Realm.add<A>(_:update:) + 284 (<compiler-generated>:284)
HI @anlaital which version of Realm are you using at the moment?
@dianaafanador3 we are using Realm v10.24.1 on iOS, which is the platform experiencing these crashes. Android has no crashes whatsoever and they are using an older Java Realm version v10.5.1.
We added some fixes for some data corruption crashes on large files on 10.2.4.2
, I would recommend to update to our latest version 10.25.2
, and if you are still experiencing these issues we can try to reproduce it on our side.
Updating won't help correct the realms that already have corruption though. There is also no API for detecting corruption. If there is corrupt data, realm will just crash because of an assertion and there is nothing you can do about it except for deleting the realm.
In my case I was able to get a hold of one user that had the problem and extract a realm file. Using Realm.writeCopy didn't work since it would also crash. But using FileManager I was able to give him a special build that didn't use any realm apis, extract the file and remove the corrupted entries manually using Realm Studio.
The user won't be able to use the corrupted realm, so delete and reinstall (with possible data loss) seems to be the only option here.
Is there any way to detect corruption? I am struggling with the error logs coming up without being able to reproduce it.
@shimastripe I don't think you won't be able to reproduce this. The transaction causing corrupted data could have happened anywhere. I am seeing fewer issues now than I did in the 10.22.0 update, but I still have customers reaching out every week with realms that are corrupted :/ I don't know if that is because they were using the 10.22.0 update and then waited to reach out or if this is still an issue.
I was in contact with support and since Realm is using hard asserts when bad data is discovered I can not provide the user with an error dialog informing them that there is a problem with their data. The ticket was basically closed as a won't fix as the app probably won't function anyway with corrupt data in there and the assertion would be justified. But it does lead to a bad user experience. All I can do is wait for the negative reviews and angry customers to reach out :(
Still getting crashes here. It is rare but it happens. And for those that have the issue, it happens repetitively. Here is a new stack trace
3 MyApp 0x6ce598 realm::util::terminate(char const*, char const*, long, std::initializer_list<realm::util::Printable>&&) + 147 (terminate.cpp:147)
4 MyApp 0x6ce8d8 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 142 (terminate.cpp:142)
5 MyApp 0x6cea54 realm::util::terminate_with_info(char const*, char const*, long, char const*, std::initializer_list<realm::util::Printable>&&) + 163 (terminate.cpp:163)
6 MyApp 0x49dc34 realm::GroupWriter::FreeList::merge_adjacent_entries_in_freelist() + 637 (group_writer.cpp:637)
7 MyApp 0x4a82fc realm::StringIndex::do_insert(realm::ObjKey, int, unsigned long, realm::StringData, realm::Mixed const&) + 861 (index_string.cpp:861)
8 MyApp 0x4a7ea0 realm::StringIndex::do_insert(realm::ObjKey, int, unsigned long, realm::StringData, realm::Mixed const&) + 799 (index_string.cpp:799)
9 MyApp 0x4a7720 realm::StringIndex::TreeInsert(realm::ObjKey, int, unsigned long, realm::StringData, realm::Mixed const&) + 743 (index_string.cpp:743)
10 MyApp 0x68a084 void realm::StringIndex::insert<realm::StringData>(realm::ObjKey, realm::StringData) + 415 (index_string.hpp:415)
11 MyApp 0x68a6c8 realm::Table::update_indexes(realm::ObjKey, realm::FieldValues const&) + 824 (table.cpp:824)
12 MyApp 0x47f0c8 realm::ClusterTree::insert(realm::ObjKey, realm::FieldValues const&) + 104 (cluster_tree.hpp:104)
13 MyApp 0x69d894 realm::TableClusterTree::insert(realm::ObjKey, realm::FieldValues const&) + 47 (table_cluster_tree.cpp:47)
14 MyApp 0x6935cc realm::Table::create_object_with_primary_key(realm::Mixed const&, realm::FieldValues&&, realm::Table::UpdateMode, bool*) + 3083 (table.cpp:3083)
15 MyApp 0x30fb14 realm::Table::create_object_with_primary_key(realm::Mixed const&, bool*) + 485 (vector:485)
16 MyApp 0x305040 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*) + 306 (object_accessor.hpp:306)
17 MyApp 0x304a14 RLMAccessorContext::createObject(objc_object*, realm::CreatePolicy, bool, realm::ObjKey) + 1102 (RLMAccessor.mm:1102)
18 MyApp 0x35512c RLMCreateObjectInRealmWithValue + 133 (RLMObjectStore.mm:133)
19 MyApp 0x80c5b0 Realm.create<A>(_:value:update:) + 611 (Realm.swift:611)
Hello,
I'm getting these crashes pretty often
private let queue = DispatchQueue(label: "StoragePerformerQueue", qos: .userInteractive)
func add(_ objects: [Object]) {
guard let db = self.db else {
Logger.log(.debug, logItem: "Realm writing error: DB is nil")
return
}
queue.async {
do {
try db.write {
objects.forEach {
db.add($0)
}
}
} catch let error {
Logger.log(.debug, logItem: "Realm writing error: \(error)")
}
}
}
Sometimes it crashes and indicates at line db.add($0) - not 'catch' block
but can it be related to situation when object with same id exists already?