Skip to content

Commit

Permalink
Fix segmentation fault
Browse files Browse the repository at this point in the history
When creating a class that extends Realm.Object and pushing the instantiated object to a list, a segmentation fault would occur.

The problem is that realm was assuming that if the object is of type Realm.Object that it has already been created. This assumption was causing a null pointer to be dereferenced which had caused the segmentation fault. The logic now checks for null and throws an exception.

Also attempting to create an object with an unmanged instance of Realm.Object will throw an exception. This is to avoid future attempts to create which fail, as the prototype has been changed.
  • Loading branch information
takameyer committed Feb 25, 2021
1 parent dd6e1aa commit e9c0533
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 39 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ x.x.x Release notes (yyyy-MM-dd)

### Fixed
* <How to hit and notice issue? what was the impact?> ([#????](https://github.com/realm/realm-js/issues/????), since v?.?.?)
* None.
* When creating a class that extends Realm.Object and pushing the instantiated object to a list, a segmentation fault would occur. This has been fixed by a null check and throwing an exception.
* Creating an object from an instance of Realm.Object that was manually constructed (detached from Realm) would fail the second time. Now we throw an meaningful exception the first time.

### Compatibility
* MongoDB Realm Cloud.
Expand Down
3 changes: 3 additions & 0 deletions src/js_object_accessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -360,6 +360,9 @@ struct Unbox<JSEngine, Obj> {
auto object = Value::validated_to_object(ctx->m_ctx, value);
if (js::Object<JSEngine>::template is_instance<RealmObjectClass<JSEngine>>(ctx->m_ctx, object)) {
auto realm_object = get_internal<JSEngine, RealmObjectClass<JSEngine>>(ctx->m_ctx, object);
if(!realm_object){
throw std::runtime_error("Cannot reference a detached instance of Realm.Object");
}
if (realm_object->realm() == ctx->m_realm) {
return realm_object->obj();
}
Expand Down
7 changes: 7 additions & 0 deletions src/js_realm.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1026,6 +1026,13 @@ void RealmClass<T>::create(ContextType ctx, ObjectType this_object, Arguments &a
object = Schema<T>::dict_for_property_array(ctx, object_schema, object);
}

if (Object::template is_instance<RealmObjectClass<T>>(ctx, object)) {
auto realm_object = get_internal<T, RealmObjectClass<T>>(ctx, object);
if(!realm_object){
throw std::runtime_error("Cannot create an object from a detached Realm.Object instance");
}
}

NativeAccessor accessor(ctx, realm, object_schema);
auto realm_object = realm::Object::create<ValueType>(accessor, realm, object_schema, object, policy);
return_value.set(RealmObjectClass<T>::create_instance(ctx, std::move(realm_object)));
Expand Down
57 changes: 57 additions & 0 deletions tests/js/list-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -1601,4 +1601,61 @@ module.exports = {
});
realm.close();
},

testClassObjectCreationOnPush: function() {
class TodoItem extends Realm.Object {
constructor(description) {
super()
this.id = new ObjectId()
this.description = description;
this.done = false;
}
}

TodoItem.schema = {
name: "TodoItem",
properties: {
id: "objectId",
description: "string",
done: {type: "bool", default: false},
deadline: "date?"
},
primaryKey: "id"
}

class TodoList extends Realm.Object {
constructor(name) {
super()
this.id = new ObjectId()
this.name = name;
this.items = []
}
}

TodoList.schema = {
name: "TodoList",
properties: {
id: "objectId",
name: "string",
items: "TodoItem[]"
},
primaryKey: "id"
}

const realm = new Realm({schema: [TodoList, TodoItem]});
realm.write(() => {
const list = realm.create(TodoList, {
id: new ObjectId(),
name: 'MyTodoList'
})

TestCase.assertThrows(() => {
list.items.push(new TodoItem("Fix that bug"))
}, "Cannot reference a detached instance of Realm.Object")

TestCase.assertThrows(() => {
realm.create(TodoItem, new TodoItem("Fix that bug"))
}, "Cannot create an object from a detached Realm.Object instance")
})
}
};
56 changes: 18 additions & 38 deletions tests/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit e9c0533

Please sign in to comment.