realm / realm-core

Core database component for the Realm Mobile Database SDKs
https://realm.io
Apache License 2.0
1.02k stars 158 forks source link

Assertion failure when rolling back transaction that removed table #1502

Closed bdash closed 8 years ago

bdash commented 8 years ago

A user reported hitting an assertion failure below Table::connect_opposite_link_columns when an exception caused a migration transaction that had removed a table to be rolled back. The stack trace form assertion failure looks like so:

realm-core/src/realm/column_linkbase.hpp:128: [realm-core-0.96.1] Assertion failed: !m_target_table
0   realm_unit_tests                    0x0000000100f54503 realm::util::terminate_internal(std::__1::basic_stringstream<char, std::__1::char_traits<char>, std::__1::allocator<char> >&) + 35
1   realm_unit_tests                    0x0000000100f54e86 realm::util::terminate(char const*, char const*, long) + 1462
2   realm_unit_tests                    0x0000000100f2893e realm::LinkColumnBase::set_target_table(realm::Table&) + 78
3   realm_unit_tests                    0x0000000100f04788 realm::Table::connect_opposite_link_columns(unsigned long, realm::Table&, unsigned long) + 104
4   realm_unit_tests                    0x0000000100f0656f realm::Table::refresh_column_accessors(unsigned long) + 1231
5   realm_unit_tests                    0x0000000100f25bef realm::Table::refresh_accessor_tree() + 479
6   realm_unit_tests                    0x00000001004b0655 realm::_impl::TableFriend::refresh_accessor_tree(realm::Table&) + 21
7   realm_unit_tests                    0x0000000100cd01af realm::Group::refresh_dirty_accessors() + 207
8   realm_unit_tests                    0x0000000100cd036c realm::Group::advance_transact(unsigned long, unsigned long, realm::_impl::NoCopyInputStream&) + 380
9   realm_unit_tests                    0x00000001003d354d realm::_impl::GroupFriend::advance_transact(realm::Group&, unsigned long, unsigned long, realm::_impl::NoCopyInputStream&) + 45
10  realm_unit_tests                    0x00000001003dac65 void realm::SharedGroup::rollback_and_continue_as_read<realm::_impl::NullInstructionObserver>(realm::History&, realm::_impl::NullInstructionObserver*) + 677
11  realm_unit_tests                    0x00000001003da9b5 void realm::_impl::SharedGroupFriend::rollback_and_continue_as_read<realm::_impl::NullInstructionObserver>(realm::SharedGroup&, realm::History&, realm::_impl::NullInstructionObserver*) + 37
12  realm_unit_tests                    0x00000001003c7759 realm::LangBindHelper::rollback_and_continue_as_read(realm::SharedGroup&, realm::History&) + 41

This can be reproduced using the following core unit test:

diff --git a/test/test_lang_bind_helper.cpp b/test/test_lang_bind_helper.cpp
index b0ed04a..bb71728 100644
--- a/test/test_lang_bind_helper.cpp
+++ b/test/test_lang_bind_helper.cpp
@@ -11161,6 +11161,42 @@ TEST(LangBindHelper_TableViewClear)
         CHECK_EQUAL(number_of_history, history->size());
         CHECK_EQUAL(number_of_line, line->size());
     }
+
+}
+
+
+// Assertion failure below Table::connect_opposite_link_columns when rolling back a transaction
+// that removed a table that contains multiple link columns.
+// Reduced from a user-provided test case at <https://secure.helpscout.net/conversation/172593782/3081/>.
+TEST(LangBindHelper_RollBackAfterRemovalOfTable)
+{
+    SHARED_GROUP_TEST_PATH(path);
+    std::unique_ptr<ClientHistory> hist(realm::make_client_history(path, crypt_key()));
+    SharedGroup sg_w(*hist, SharedGroup::durability_Full, crypt_key());
+    Group& group_w = const_cast<Group&>(sg_w.begin_read());
+
+    {
+        LangBindHelper::promote_to_write(sg_w, *hist);
+
+        TableRef source_a = group_w.add_table("source_a");
+        TableRef source_b = group_w.add_table("source_b");
+        TableRef target_a = group_w.add_table("target_a");
+        TableRef target_b = group_w.add_table("target_b");
+
+        source_a->add_column_link(type_Link, "a", *target_a);
+        source_a->add_column_link(type_LinkList, "b", *target_b);
+
+        source_b->add_column_link(type_LinkList, "b", *target_b);
+
+        LangBindHelper::commit_and_continue_as_read(sg_w);
+    }
+
+    {
+        LangBindHelper::promote_to_write(sg_w, *hist);
+
+        group_w.remove_table("source_a");
+        LangBindHelper::rollback_and_continue_as_read(sg_w, *hist);
+   }
 }

 #endif
ironage commented 8 years ago

Thank you for the reproducible test case: this is gold!