Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Crash when modifying linked objects of observed sectioned result #5912

Closed
sereivoanyong opened this issue Sep 30, 2022 · 5 comments · Fixed by #5926
Closed

Crash when modifying linked objects of observed sectioned result #5912

sereivoanyong opened this issue Sep 30, 2022 · 5 comments · Fixed by #5926
Assignees
Labels
More-information-needed More information is needed to progress. The issue will close automatically in 2 weeks. O-Community

Comments

@sereivoanyong
Copy link

SDK and version

SDK : Cocoa
Version: 10.30.0

Observations

  • How frequent do the crash occur? Always
  • Does it happen in production or during dev/test? All
  • Can the crash be reproduced by you? Yes
  • Can you provide instructions for how we can reproduce it?

I have 2 classes Transaction (contains date: Date, account: Account!) and Account (contains name: String).

I got a List<Transaction> and filter its date in specific month and then section by Calendar.current.startOfDay(for:) on its date. The app then crashes when I try to update the name of transaction.account.

Crash log / stacktrace

.../realm-core/src/realm/object-store/sectioned_results.cpp:86: [realm-core-12.7.0] Assertion failed: it != m_sectioned_results.m_prev_section_index_to_key.end()
0 LuyBuddy 0x00000001044c5e8c _ZN5realm4utilL18terminate_internalERNSt3__118basic_stringstreamIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE + 28
1 LuyBuddy 0x00000001044c5d2e _ZN5realm4util9terminateEPKcS2_lOSt16initializer_listINS0_9PrintableEE + 238
2 LuyBuddy 0x0000000103f17dd5 _ZN5realm35SectionedResultsNotificationHandlerclERKNS_19CollectionChangeSetE + 661
3 LuyBuddy 0x0000000103f17af1 _ZN5realm24CollectionChangeCallback4ImplINS_35SectionedResultsNotificationHandlerEE5afterERKNS_19CollectionChangeSetE + 33
4 LuyBuddy 0x0000000103e1dd76 _ZN5realm24CollectionChangeCallback5afterERKNS_19CollectionChangeSetE + 38
5 LuyBuddy 0x0000000103e1dca2 _ZZN5realm5_impl18CollectionNotifier13after_advanceEvENK3$6clINS_4util17CheckedUniqueLockENS0_20NotificationCallbackEEEDaRT_RT0 + 466
6 LuyBuddy 0x0000000103e11358 _ZN5realm5_impl18CollectionNotifier17for_each_callbackIZNS1_13after_advanceEvE3$6EEvOT + 232
7 LuyBuddy 0x0000000103e11269 _ZN5realm5_impl18CollectionNotifier13after_advanceEv + 25
8 LuyBuddy 0x0000000103e43c6e _ZN5realm5_impl16RealmCoordinator23process_available_asyncERNS_5RealmE + 1054
9 LuyBuddy 0x0000000103fa9fc0 _ZN5realm5Realm6notifyEv + 352
10 LuyBuddy 0x0000000103e8ad60 _ZZN5realm5_impl17WeakRealmNotifier6notifyEvENK3$_0clEv + 64
11 LuyBuddy 0x0000000103e8ad15 _ZN5realm4util14UniqueFunctionIFvvEE17call_regular_voidIZNS_5_impl17WeakRealmNotifier6notifyEvE3$0EEvNSt3__117integral_constantIbLb1EEERT + 21
12 LuyBuddy 0x0000000103e8ac19 _ZN5realm4util14UniqueFunctionIFvvEE12SpecificImplIZNS_5_impl17WeakRealmNotifier6notifyEvE3$_0E4callEv + 25
13 LuyBuddy 0x0000000103c6360a _ZNK5realm4util14UniqueFunctionIFvvEEclEv + 106
14 LuyBuddy 0x00000001040d182b _ZN5realm4util15InvocationQueue10invoke_allEv + 155
15 LuyBuddy 0x00000001040d22b9 _ZZN5realm4util16RunLoopSchedulerC1EP11__CFRunLoopENK3$_0clEPv + 25
16 LuyBuddy 0x00000001040d2295 _ZZN5realm4util16RunLoopSchedulerC1EP11__CFRunLoopEN3$_08__invokeEPv + 21
17 CoreFoundation 0x000000010cb36ebd CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
18 CoreFoundation 0x000000010cb36dfc __CFRunLoopDoSource0 + 157
19 CoreFoundation 0x000000010cb36659 __CFRunLoopDoSources0 + 308
20 CoreFoundation 0x000000010cb30db3 __CFRunLoopRun + 927
21 CoreFoundation 0x000000010cb30637 CFRunLoopRunSpecific + 560
22 GraphicsServices 0x000000011297428a GSEventRunModal + 139
23 UIKitCore 0x00000001215f9425 -[UIApplication _run] + 994
24 UIKitCore 0x00000001215fe301 UIApplicationMain + 123
25 libswiftUIKit.dylib 0x000000010ddfdc02 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
26 LuyBuddy 0x00000001034d8ce8 $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 104
27 LuyBuddy 0x00000001034d8c6c $s8LuyBuddy11AppDelegateC5$mainyyFZ + 28
28 LuyBuddy 0x00000001034e2748 main + 24
29 dyld 0x00000001090bc2bf start_sim + 10
30 ??? 0x000000011299f52e 0x0 + 4607046958!!! IMPORTANT: Please report this at https://github.com/realm/realm-core/issues/new/choose2022-09-30 14:06:43.413222+0700 LuyBuddy[37105:263587] /Users/sereivoanyong/Library/Developer/Xcode/DerivedData/LuyBuddy-dgzlfwcubyoaydgaoojlhkyizypn/SourcePackages/checkouts/realm-core/src/realm/object-store/sectioned_results.cpp:86: [realm-core-12.7.0] Assertion failed: it != m_sectioned_results.m_prev_section_index_to_key.end()
0 LuyBuddy 0x00000001044c5e8c _ZN5realm4utilL18terminate_internalERNSt3__118basic_stringstreamIcNS1_11char_traitsIcEENS1_9allocatorIcEEEE + 28
1 LuyBuddy 0x00000001044c5d2e _ZN5realm4util9terminateEPKcS2_lOSt16initializer_listINS0_9PrintableEE + 238
2 LuyBuddy 0x0000000103f17dd5 _ZN5realm35SectionedResultsNotificationHandlerclERKNS_19CollectionChangeSetE + 661
3 LuyBuddy 0x0000000103f17af1 _ZN5realm24CollectionChangeCallback4ImplINS_35SectionedResultsNotificationHandlerEE5afterERKNS_19CollectionChangeSetE + 33
4 LuyBuddy 0x0000000103e1dd76 _ZN5realm24CollectionChangeCallback5afterERKNS_19CollectionChangeSetE + 38
5 LuyBuddy 0x0000000103e1dca2 _ZZN5realm5_impl18CollectionNotifier13after_advanceEvENK3$6clINS_4util17CheckedUniqueLockENS0_20NotificationCallbackEEEDaRT_RT0 + 466
6 LuyBuddy 0x0000000103e11358 _ZN5realm5_impl18CollectionNotifier17for_each_callbackIZNS1_13after_advanceEvE3$6EEvOT + 232
7 LuyBuddy 0x0000000103e11269 _ZN5realm5_impl18CollectionNotifier13after_advanceEv + 25
8 LuyBuddy 0x0000000103e43c6e _ZN5realm5_impl16RealmCoordinator23process_available_asyncERNS_5RealmE + 1054
9 LuyBuddy 0x0000000103fa9fc0 _ZN5realm5Realm6notifyEv + 352
10 LuyBuddy 0x0000000103e8ad60 _ZZN5realm5_impl17WeakRealmNotifier6notifyEvENK3$_0clEv + 64
11 LuyBuddy 0x0000000103e8ad15 _ZN5realm4util14UniqueFunctionIFvvEE17call_regular_voidIZNS_5_impl17WeakRealmNotifier6notifyEvE3$0EEvNSt3__117integral_constantIbLb1EEERT + 21
12 LuyBuddy 0x0000000103e8ac19 _ZN5realm4util14UniqueFunctionIFvvEE12SpecificImplIZNS_5_impl17WeakRealmNotifier6notifyEvE3$_0E4callEv + 25
13 LuyBuddy 0x0000000103c6360a _ZNK5realm4util14UniqueFunctionIFvvEEclEv + 106
14 LuyBuddy 0x00000001040d182b _ZN5realm4util15InvocationQueue10invoke_allEv + 155
15 LuyBuddy 0x00000001040d22b9 _ZZN5realm4util16RunLoopSchedulerC1EP11__CFRunLoopENK3$_0clEPv + 25
16 LuyBuddy 0x00000001040d2295 _ZZN5realm4util16RunLoopSchedulerC1EP11__CFRunLoopEN3$_08__invokeEPv + 21
17 CoreFoundation 0x000000010cb36ebd CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
18 CoreFoundation 0x000000010cb36dfc __CFRunLoopDoSource0 + 157
19 CoreFoundation 0x000000010cb36659 __CFRunLoopDoSources0 + 308
20 CoreFoundation 0x000000010cb30db3 __CFRunLoopRun + 927
21 CoreFoundation 0x000000010cb30637 CFRunLoopRunSpecific + 560
22 GraphicsServices 0x000000011297428a GSEventRunModal + 139
23 UIKitCore 0x00000001215f9425 -[UIApplication _run] + 994
24 UIKitCore 0x00000001215fe301 UIApplicationMain + 123
25 libswiftUIKit.dylib 0x000000010ddfdc02 $s5UIKit17UIApplicationMainys5Int32VAD_SpySpys4Int8VGGSgSSSgAJtF + 98
26 LuyBuddy 0x00000001034d8ce8 $sSo21UIApplicationDelegateP5UIKitE4mainyyFZ + 104
27 LuyBuddy 0x00000001034d8c6c $s8LuyBuddy11AppDelegateC5$mainyyFZ + 28
28 LuyBuddy 0x00000001034e2748 main + 24
29 dyld 0x00000001090bc2bf start_sim + 10
30 ??? 0x000000011299f52e 0x0 + 4607046958!!! IMPORTANT: Please report this at https://github.com/realm/realm-core/issues/new/choose

Steps & Code to Reproduce

final class Transaction: Object {

  @Persisted var date: Date
  @Persisted var account: Account!

  var startOfDate: Date {
    return Calendar.current.startOfDay(for: date)
  }
}

final class Account: Object {

  @Persisted var name: String
}

/// I have a view controller observing this
realm.objects(Transaction.self)
  .filter("date BETWEEN %@", // date range //)
  .sectioned(by: \.startOfDate, ascending: false)

/// It then crashes when I try to update `account` linked to one of above transaction in another view controller.
/// It works just fine if I don't section the transactions.
@ironage
Copy link
Contributor

ironage commented Oct 1, 2022

Thanks for reporting this @sereivoanyong.
The assertion is not immediately reproducible from the information you provided. Are you doing anything else in the transaction that updates the linked object? Are you able to provide a minimal runnable reproduction case?

@ironage ironage added Waiting-For-Reporter Waiting for more information from the reporter before we can proceed More-information-needed More information is needed to progress. The issue will close automatically in 2 weeks. labels Oct 1, 2022
@ironage
Copy link
Contributor

ironage commented Oct 1, 2022

Internal note, here's the test I tried which succeeded:

    SECTION("notifications from a linked object") {
        Query filter = table->where().ends_with(name_col, StringData("PASS"), true);
        auto filtered_results = sorted.filter(std::move(filter));
        auto sectioned_results = filtered_results.sectioned_results([](Mixed value, SharedRealm realm) {
            auto obj = Object(realm, value.get_link());
            auto v = obj.get_column_value<StringData>("name_col");
            return v.prefix(1);
        });

        SectionedResultsChangeSet changes;
        auto token = sectioned_results.add_notification_callback([&](SectionedResultsChangeSet c) {
            changes = c;
        });

        coordinator->on_change();

        // Insertions
        r->begin_transaction();
        auto s1 = table->create_object().set(name_col, "James PASS");
        auto s2 = table->create_object().set(name_col, "John PASS");
        auto s3 = table->create_object().set(name_col, "Jonathan PASS");
        auto s4 = table->create_object().set(name_col, "Adam PASS");
        auto s5 = table->create_object().set(name_col, "Alex PASS");
        auto d1 = dest_table->create_object().set(dest_name_col, "dest one");
        r->commit_transaction();
        advance_and_notify(*r);

        REQUIRE(changes.sections_to_insert.count() == 2);
        REQUIRE(changes.sections_to_delete.count() == 0);
        REQUIRE_INDICES(changes.sections_to_insert, 0, 1);

        REQUIRE(changes.insertions.size() == 2);
        // Section 0 is 'A'
        REQUIRE_INDICES(changes.insertions[0], 0, 1);
        REQUIRE(changes.insertions[0].count() == 2);
        // Section 1 is 'J'
        REQUIRE(changes.insertions[1].count() == 3);
        REQUIRE_INDICES(changes.insertions[1], 0, 1, 2);
        REQUIRE(changes.modifications.empty());
        REQUIRE(changes.deletions.empty());

        // Setting a top level link is a modification
        r->begin_transaction();
        o1.set(link_col, d1.get_key());
        s1.set(link_col, d1.get_key());
        s2.set(link_col, d1.get_key());
        s3.set(link_col, d1.get_key());
        s4.set(link_col, d1.get_key());
        s5.set(link_col, d1.get_key());
        r->commit_transaction();
        advance_and_notify(*r);
        REQUIRE(changes.sections_to_insert.count() == 0);
        REQUIRE(changes.sections_to_delete.count() == 0);

        REQUIRE(changes.modifications.size() == 2);
        REQUIRE_INDICES(changes.modifications[0], 0, 1);
        REQUIRE_INDICES(changes.modifications[1], 0, 1, 2);
        REQUIRE(changes.insertions.empty());
        REQUIRE(changes.deletions.empty());

        changes = {};
        r->begin_transaction();
        d1.set(dest_name_col, "a linked modification");
        r->commit_transaction();
        advance_and_notify(*r);
        REQUIRE(changes.sections_to_insert.count() == 0);
        REQUIRE(changes.sections_to_delete.count() == 0);

        REQUIRE(changes.modifications.size() == 2);
        REQUIRE_INDICES(changes.modifications[0], 0, 1);
        REQUIRE_INDICES(changes.modifications[1], 0, 1, 2);
        REQUIRE(changes.insertions.empty());
        REQUIRE(changes.deletions.empty());
    }

@sereivoanyong
Copy link
Author

@ironage Hi. Here's the full crash-reproducible code in Swift.

import UIKit
import RealmSwift

final class Transaction: Object {

  @Persisted(primaryKey: true) var _id: String

  @Persisted var date: Date

  @Persisted var account: Account!
}

final class Account: Object {

  @Persisted(primaryKey: true) var _id: String

  @Persisted var name: String
}

class ViewController: UIViewController {

  var notification: NotificationToken!

  override func viewDidLoad() {
    super.viewDidLoad()

    let realm = try! Realm()
    try! realm.write {
      realm.deleteAll()
    }
    try! realm.write {
      let t = Transaction()
      t._id = "t"
      let a = Account()
      a._id = "a"
      t.account = a
      realm.add(t)
    }

    /// Works fine here
//    notification = realm.objects(Transaction.self).observe({ c in
//      print(c)
//    })

    // Crash
    notification = realm.objects(Transaction.self).sectioned(by: {
      Calendar.current.startOfDay(for: $0.date)
    }, sortDescriptors: [SortDescriptor(keyPath: "date", ascending: false)]).observe({ c in
      print(c)
    })

    DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
      let account = realm.object(ofType: Account.self, forPrimaryKey: "a")!
      try! realm.write {
        account.name = "a2"
      }
    }
  }
}

@github-actions github-actions bot added Needs-Attention Reporter has responded. Review comment. and removed Waiting-For-Reporter Waiting for more information from the reporter before we can proceed labels Oct 2, 2022
@sereivoanyong
Copy link
Author

It always crashes when updating any accounts linked to observed sectioned transactions.

@ironage
Copy link
Contributor

ironage commented Oct 3, 2022

@sereivoanyong thanks for that, I am able to reproduce this now. @leemaguire could you take a look at this?

TEST_CASE("sectioned results link notification bug", "[sectioned_results]") {
    _impl::RealmCoordinator::assert_no_open_realms();

    InMemoryTestFile config;
    config.automatic_change_notifications = false;

    auto r = Realm::get_shared_realm(config);
    r->update_schema({
        {"Transaction",
            {{"_id", PropertyType::String, Property::IsPrimary{true}},
                {"date", PropertyType::Date},
                {"account", PropertyType::Object | PropertyType::Nullable, "Account"}}},
        {"Account",
            {{"_id", PropertyType::String, Property::IsPrimary{true}},
            {"name", PropertyType::String}
        }}
    });

    auto coordinator = _impl::RealmCoordinator::get_coordinator(config.path);
    auto transaction_table = r->read_group().get_table("class_Transaction");
    auto date_col = transaction_table->get_column_key("date");
    auto account_col = transaction_table->get_column_key("account");
    auto account_table = r->read_group().get_table("class_Account");
    auto account_name_col = account_table->get_column_key("name");

    r->begin_transaction();
    auto t1 = transaction_table->create_object_with_primary_key("t");
    auto a1 = account_table->create_object_with_primary_key("a");
    t1.set(account_col, a1.get_key());
    r->commit_transaction();

    Results results(r, transaction_table);
    auto sorted = results.sort({{"date", false}});
    auto sectioned_results = sorted.sectioned_results([](Mixed value, SharedRealm realm) {
        auto obj = Object(realm, value.get_link());
        auto ts = obj.get_column_value<Timestamp>("date");
        auto tp = ts.get_time_point();
        auto day = std::chrono::floor<std::chrono::hours>(tp);
        return Timestamp{day};
    });

    REQUIRE(sectioned_results.size() == 1);
    REQUIRE(sectioned_results[0].size() == 1);

    SectionedResultsChangeSet changes;
    auto token = sectioned_results.add_notification_callback([&](SectionedResultsChangeSet c) {
        changes = c;
    });
    coordinator->on_change();

    r->begin_transaction();
    a1.set(account_name_col, "a2");
    r->commit_transaction();
    advance_and_notify(*r);
}

@sync-by-unito sync-by-unito bot removed the Needs-Attention Reporter has responded. Review comment. label Oct 3, 2022
@ironage ironage mentioned this issue Oct 6, 2022
3 tasks
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 21, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
More-information-needed More information is needed to progress. The issue will close automatically in 2 weeks. O-Community
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants