Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deleting a bunch of objects at once may cause a crash in migration #5546

Open
anlaital opened this issue Jan 2, 2018 · 7 comments
Open

Deleting a bunch of objects at once may cause a crash in migration #5546

anlaital opened this issue Jan 2, 2018 · 7 comments

Comments

@anlaital
Copy link

anlaital commented Jan 2, 2018

Goals

Delete objects in a migration.

Expected Results

Objects get deleted.

Actual Results

Realm crashes with the following stack trace:

image

This crash is caused by the following method (array index out-of-bounds):

- (void)deleteObjectsMarkedForDeletion {
    for (NSString *className in deletedObjectIndices.allKeys) {
        RLMResults *objects = [_realm allObjects:className]; // objects.count == 811 at start, decreasing by one with each deletion as this is a self-updating type
        for (NSNumber *index in deletedObjectIndices[className]) {
            // here the sort order is random (or implicitly user-defined); this means that lower indices may get deleted before higher ones, causing the crash
            RLMObject *object = objects[index.longValue]; 
            [_realm deleteObject:object];
        }
    }
}

Here's a very simple fixed version that sorts the indices before looping (this fixes the crash, haven't verified that it works semantically correctly):

- (void)deleteObjectsMarkedForDeletion {
    for (NSString *className in deletedObjectIndices.allKeys) {
        RLMResults *objects = [_realm allObjects:className];
        // Delete objects with indices sorted in descending order to prevent array index out-of-bounds crashes.
        NSSortDescriptor *sort = [[NSSortDescriptor alloc] initWithKey:nil ascending:NO];
        NSArray *sortedIndices = [deletedObjectIndices[className] sortedArrayUsingDescriptors:@[sort]];
        for (NSNumber *index in sortedIndices) {
            RLMObject *object = objects[index.longValue];
            [_realm deleteObject:object];
        }
    }
}

Version of Realm and Tooling

Realm framework version: 3.0.2

@bdash
Copy link
Contributor

bdash commented Jan 2, 2018

Can you please share some code that reproduces the issue so we'll be able to verify that whatever fix we make addresses the problem you're encountering?

@anlaital
Copy link
Author

anlaital commented Jan 2, 2018

This was simple to reproduce. First create some data (doesn't matter what the data is):

class O: Object {
    
    @objc dynamic var i = 0
    
}

var conf = Realm.Configuration.defaultConfiguration

let realm = try! Realm(configuration: conf)

try! realm.write {
    for _ in 0..<1000 {
        realm.add(O())
    }
}

Then increment version number and implement the following migration block:

conf.schemaVersion = 1
conf.migrationBlock = {
    migration, oldSchemaVersion in
    
    var toDelete = [MigrationObject]()
    
    migration.enumerateObjects(ofType: O.className()) {
        oldObject, newObject in
        toDelete.append(newObject!)
    }
    
    // deleting objects in reversed order causes the crash
    for object in toDelete.reversed() {
        migration.delete(object)
    }
}

@bdash
Copy link
Contributor

bdash commented Jan 2, 2018

Thank you!

@fmorau
Copy link

fmorau commented May 22, 2020

@anlaital did you find any workaround for this? :)

@anlaital
Copy link
Author

Maintaining the enumeration order when deleting the objects doesn't crash.

@fmorau
Copy link

fmorau commented May 22, 2020

@anlaital 👍🏻👍🏻 Thank you, will try :)

@RetVal
Copy link

RetVal commented Dec 27, 2024

any updates of this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants