realm-core: A case of either encryption bug or file corruption
User filed realm/realm-cocoa#3519 and shared the encryption key and Realm file in Helpscout here: https://secure.helpscout.net/conversation/198591481/4056
I can reproduce the crash when opening with this minimal Realm Swift code:
let fileURL = NSBundle.mainBundle().URLForResource("3519", withExtension: "realm")!
let encryptionKeyBytes: [UInt8] = [0x61, 0x64, 0x66, 0x63, 0x33, 0x66, 0x64, 0x30,
0x66, 0x35, 0x61, 0x35, 0x37, 0x39, 0x64, 0x34,
0x61, 0x32, 0x30, 0x62, 0x62, 0x33, 0x34, 0x33,
0x63, 0x38, 0x32, 0x32, 0x35, 0x35, 0x64, 0x38,
0x31, 0x39, 0x30, 0x64, 0x61, 0x64, 0x35, 0x36,
0x38, 0x33, 0x38, 0x61, 0x38, 0x38, 0x30, 0x64,
0x30, 0x34, 0x31, 0x64, 0x63, 0x62, 0x33, 0x62,
0x37, 0x61, 0x33, 0x39, 0x61, 0x39, 0x36, 0x38]
let encryptionKey = NSData(bytes: encryptionKeyBytes, length: encryptionKeyBytes.count)
let configuration = Realm.Configuration(fileURL: fileURL, encryptionKey: encryptionKey, readOnly: true)
do {
let realm = try Realm(configuration: configuration)
print("Opened Realm successfully: \(realm)")
} catch {
print("Error opening Realm: \(error)")
}
which produces the following stack trace:
* thread #1: tid = 0xfc2b4, 0x00000001056e2965 Realm`realm::Table::has_search_index(unsigned long) const + 37, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
frame #0: 0x00000001056e2965 Realm`realm::Table::has_search_index(unsigned long) const + 37
frame #1: 0x00000001054b3565 Realm`realm::ObjectSchema::ObjectSchema(realm::Group const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&) + 557
frame #2: 0x00000001054b6e19 Realm`realm::ObjectStore::schema_from_group(realm::Group const*) + 379
frame #3: 0x000000010556ba03 Realm`realm::Realm::init(std::__1::shared_ptr<realm::_impl::RealmCoordinator>) + 281
frame #4: 0x00000001054bc6a5 Realm`realm::_impl::RealmCoordinator::get_realm(realm::Realm::Config) + 617
frame #5: 0x000000010556c3a0 Realm`realm::Realm::get_shared_realm(realm::Realm::Config) + 266
frame #6: 0x0000000105559981 Realm`+[RLMRealm openSharedRealm:error:] + 69
frame #7: 0x0000000105559d5d Realm`+[RLMRealm realmWithConfiguration:error:] + 864
frame #8: 0x00000001054068b1 RealmSwift`RealmSwift.Realm.__allocating_init (configuration : RealmSwift.Realm.Configuration) throws -> RealmSwift.Realm + 977
* frame #9: 0x000000010533e041 GH3519`AppDelegate.application(application=0x00007fef394044b0, launchOptions=nil, self=0x00007fef3950be20) -> Bool + 3345 at AppDelegate.swift:24
frame #10: 0x000000010533e594 GH3519`@objc AppDelegate.application(UIApplication, didFinishLaunchingWithOptions : [NSObject : AnyObject]?) -> Bool + 180 at AppDelegate.swift:0
frame #11: 0x00000001062909ac UIKit`-[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 272
frame #12: 0x0000000106291c0d UIKit`-[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 3415
frame #13: 0x0000000106298568 UIKit`-[UIApplication _runWithMainScene:transitionContext:completion:] + 1769
frame #14: 0x0000000106295714 UIKit`-[UIApplication workspaceDidEndTransaction:] + 188
frame #15: 0x000000010aaf38c8 FrontBoardServices`__FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 24
frame #16: 0x000000010aaf3741 FrontBoardServices`-[FBSSerialQueue _performNext] + 178
frame #17: 0x000000010aaf3aca FrontBoardServices`-[FBSSerialQueue _performNextFromRunLoopSource] + 45
frame #18: 0x0000000105995301 CoreFoundation`__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
frame #19: 0x000000010598b22c CoreFoundation`__CFRunLoopDoSources0 + 556
frame #20: 0x000000010598a6e3 CoreFoundation`__CFRunLoopRun + 867
frame #21: 0x000000010598a0f8 CoreFoundation`CFRunLoopRunSpecific + 488
frame #22: 0x0000000106294f21 UIKit`-[UIApplication _run] + 402
frame #23: 0x0000000106299f09 UIKit`UIApplicationMain + 171
frame #24: 0x000000010533ea12 GH3519`main + 114 at AppDelegate.swift:13
frame #25: 0x000000010907992d libdyld.dylib`start + 1
So the bad memory access appears to happen in realm::Table::has_search_index
.
About this issue
- Original URL
- State: closed
- Created 8 years ago
- Comments: 16 (16 by maintainers)
In the realm file provided by the user, the crash occurs when trying to create a
StringColumn
that has a bad reference. Through debugging, I found that the column which is corrupted is at index 12 in table 12 (columniban
of tableclass_Transaction
). All other columns can be constructed without problems. I asked the user for their migration code in help scout and found that they encountered an issue in April 2015 which caused corruption of search indexes when using a move last over operation. The issue has since been fixed but to get around the corruption in their user data they had to abandon theTransaction
class and migrated to aTransactionV2
class. After inspecting the subspec structure of all tables in the Realm file, I noticed that the file does indeed have aclass_TransactionV2
table, but the crash is happening on the original tableclass_Transaction
in columniban
the very same property that is mentioned in the user migration code as being corrupted!First problem is that when we upgrade the Realm from DateTime to Timestamp, we create accessors to EVERY table in a loop, including this corrupted table hence the crash. (Note that “class_Transaction” does have a DateTime column anyways). Second problem is that
class_Transaction
links to another table so even if this table should not be used, it will get initialised because there is still a backlink from another table pointing to it.I don’t think it’s index related. has_search_index() just turns out to be the first method that accesses a member variable of a bad object.
I can also reproduce crashes from C++ and will look at it tomorrow