Skip to content

Commit

Permalink
Don't update backlinks in Mixed self-assignment (#7384)
Browse files Browse the repository at this point in the history
Setting a Mixed field to ObjLink equal to the current value removed the
existing backlink and then exited before adding the new one, leaving things in
an invalid state.
  • Loading branch information
tgoyne committed Feb 27, 2024
1 parent 4f82d8b commit 0ea2d64
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
### Fixed
* <How do the end-user experience this issue? what was the impact?> ([#????](https://github.com/realm/realm-core/issues/????), since v?.?.?)
* List KVO information was being populated for non-list collections ([PR #7378](https://github.com/realm/realm-core/pull/7378), since v14.0.0)
* Setting a Mixed property to an ObjLink equal to its existing value would remove the existing backlinks and then exit before re-adding them, resulting in later assertion failures due to the backlink state being invalid ([PR #7384](https://github.com/realm/realm-core/pull/7384), since v14.0.0).
* Opening file with file format 23 in read-only mode will crash ([#7388](https://github.com/realm/realm-core/issues/7388), since v14.0.0)

### Breaking changes
Expand Down
11 changes: 5 additions & 6 deletions src/realm/obj.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1168,10 +1168,11 @@ Obj& Obj::set<Mixed>(ColKey col_key, Mixed value, bool is_default)
}

Mixed old_value = get_unfiltered_mixed(col_ndx);
ObjLink old_link{};
ObjLink new_link{};
if (old_value.is_type(type_TypedLink)) {
old_link = old_value.get<ObjLink>();
if (old_value == value) {
return *this;
}
auto old_link = old_value.get<ObjLink>();
recurse = remove_backlink(col_key, old_link, state);
}
else if (old_value.is_type(type_Dictionary)) {
Expand All @@ -1187,10 +1188,8 @@ Obj& Obj::set<Mixed>(ColKey col_key, Mixed value, bool is_default)
if (m_table->is_asymmetric()) {
throw IllegalOperation("Links not allowed in asymmetric tables");
}
new_link = value.template get<ObjLink>();
auto new_link = value.get<ObjLink>();
m_table->get_parent_group()->validate(new_link);
if (new_link == old_link)
return *this;
set_backlink(col_key, new_link);
}

Expand Down
23 changes: 23 additions & 0 deletions test/test_mixed_null_assertions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -443,3 +443,26 @@ TEST(Mixed_set_non_link_assertion)
dest_obj.remove(); // triggers an assertion failure if the backlink was not removed
source_obj.remove();
}

TEST(Mixed_LinkSelfAssignment)
{
Group g;
auto source = g.add_table("source");
auto dest = g.add_table("dest");
ColKey mixed_col = source->add_column(type_Mixed, "mixed");
auto source_obj = source->create_object();
auto dest_obj = dest->create_object();

CHECK_EQUAL(dest_obj.get_backlink_count(), 0);

source_obj.set(mixed_col, Mixed{ObjLink{dest->get_key(), dest_obj.get_key()}});
CHECK_EQUAL(dest_obj.get_backlink_count(), 1);

// Re-assign the same link, which should not update backlinks
source_obj.set(mixed_col, Mixed{ObjLink{dest->get_key(), dest_obj.get_key()}});
CHECK_EQUAL(dest_obj.get_backlink_count(), 1);

dest_obj.remove();
CHECK_EQUAL(source_obj.get<Mixed>(mixed_col), Mixed());
source_obj.remove();
}

0 comments on commit 0ea2d64

Please sign in to comment.