Skip to content

Commit

Permalink
Fix segmentation fault (#3610)
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 authored Mar 8, 2021
1 parent dd6e1aa commit f4d68d6
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 1 deletion.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ 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.
* There seems to be a few issues regarding class support in realm-js. We are currently coming up with strategies to better support this in the future. In the meantime, the following fixes have been applied to help avoid crashes and failures.
* 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();
},

testClassObjectCreation: 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")
})
}
};

0 comments on commit f4d68d6

Please sign in to comment.