Skip to content

Commit 4d815c6

Browse files
danieltabacarujedelbo
authored andcommitted
Fix crash when removing dictionary key (#7569)
1 parent b14e1e4 commit 4d815c6

File tree

3 files changed

+49
-3
lines changed

3 files changed

+49
-3
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
### Fixed
44
* Fix compilation errors when using command-line `swift build` ([#7587](https://github.com/realm/realm-core/pull/7587), since v14.5.1).
5+
* Fixed crash when integrating removal of already removed dictionary key ([#7488](https://github.com/realm/realm-core/issues/7488), since v10.0.0).
56

67
### Compatibility
78
* Fileformat: Generates files with format v24. Reads and automatically upgrade from fileformat v10. If you want to upgrade from an earlier file format version you will have to use RealmCore v13.x.y or earlier.

src/realm/sync/instruction_applier.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,7 @@ void InstructionApplier::operator()(const Instruction::Update& instr)
489489
}
490490
},
491491
[&](const Instruction::Payload::Erased&) {
492-
dict.erase(key);
492+
dict.try_erase(key);
493493
},
494494
[&](const Instruction::Payload::ObjectValue&) {
495495
dict.create_and_insert_linked_object(key);

test/test_transform.cpp

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,7 +1487,6 @@ TEST(Transform_ArrayInsert_EraseObject)
14871487
client_2.get()->integrate_next_changeset_from(*server);
14881488
}
14891489

1490-
14911490
TEST(Transform_ArrayClearVsArrayClear_TimestampBased)
14921491
{
14931492
auto changeset_dump_dir_gen = get_changeset_dump_dir_generator(test_context);
@@ -2081,7 +2080,9 @@ TEST(Transform_Dictionary)
20812080
auto& tr = *c.group;
20822081
auto table = tr.add_table_with_primary_key("class_Table", type_Int, "id");
20832082
table->add_column_dictionary(type_Mixed, "dict");
2084-
table->create_object_with_primary_key(0);
2083+
auto obj0 = table->create_object_with_primary_key(0);
2084+
auto dict = obj0.get_dictionary("dict");
2085+
dict.insert("key", 42);
20852086
table->create_object_with_primary_key(1);
20862087
});
20872088

@@ -2096,6 +2097,7 @@ TEST(Transform_Dictionary)
20962097
auto dict0 = obj0.get_dictionary("dict");
20972098
auto dict1 = obj1.get_dictionary("dict");
20982099

2100+
dict0.erase("key");
20992101
dict0.insert("a", 123);
21002102
dict0.insert("b", "Hello");
21012103
dict0.insert("c", 45.0);
@@ -2112,6 +2114,7 @@ TEST(Transform_Dictionary)
21122114
auto dict0 = obj0.get_dictionary("dict");
21132115
auto dict1 = obj1.get_dictionary("dict");
21142116

2117+
dict0.erase("key");
21152118
dict0.insert("b", "Hello, World!");
21162119
dict0.insert("d", true);
21172120

@@ -2200,6 +2203,48 @@ TEST(Transform_Set)
22002203
});
22012204
}
22022205

2206+
TEST(Transform_SetEraseVsSetErase)
2207+
{
2208+
auto changeset_dump_dir_gen = get_changeset_dump_dir_generator(test_context);
2209+
auto server = Peer::create_server(test_context, changeset_dump_dir_gen.get());
2210+
auto client_1 = Peer::create_client(test_context, 2, changeset_dump_dir_gen.get());
2211+
auto client_2 = Peer::create_client(test_context, 3, changeset_dump_dir_gen.get());
2212+
2213+
// Baseline: insert one element in the set ('set' property)
2214+
client_1->create_schema([](WriteTransaction& tr) {
2215+
auto t = tr.get_group().add_table_with_primary_key("class_A", type_Int, "pk");
2216+
t->add_column_set(type_Int, "set");
2217+
auto obj = t->create_object_with_primary_key(1);
2218+
auto ss = obj.get_set<Int>("set");
2219+
ss.insert(42);
2220+
});
2221+
2222+
synchronize(server.get(), {client_1.get(), client_2.get()});
2223+
2224+
// Client 1 removes the element from the set
2225+
client_1->transaction([](Peer& p) {
2226+
auto ss = p.table("class_A")->begin()->get_set<Int>("set");
2227+
ss.erase(42);
2228+
});
2229+
2230+
// Client 2 removes the element from the set
2231+
client_2->transaction([](Peer& p) {
2232+
auto ss = p.table("class_A")->begin()->get_set<Int>("set");
2233+
ss.erase(42);
2234+
});
2235+
2236+
synchronize(server.get(), {client_1.get(), client_2.get()});
2237+
2238+
// Result: the set is empty
2239+
ReadTransaction read_server(server->shared_group);
2240+
ReadTransaction read_client_1(client_1->shared_group);
2241+
ReadTransaction read_client_2(client_2->shared_group);
2242+
CHECK(compare_groups(read_server, read_client_1));
2243+
CHECK(compare_groups(read_server, read_client_2, *test_context.logger));
2244+
auto table = read_server.get_table("class_A");
2245+
CHECK(table->begin()->get_set<Int>("set").is_empty());
2246+
}
2247+
22032248
TEST(Transform_ArrayEraseVsArrayErase)
22042249
{
22052250
// This test case recreates the problem that the above test exposes

0 commit comments

Comments
 (0)