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

Fix a race condition in notifier initialization #4234

Merged
merged 1 commit into from
Dec 18, 2020

Conversation

tgoyne
Copy link
Member

@tgoyne tgoyne commented Dec 18, 2020

Newly created notifiers copied their Query from the source Realm on the worker thread without locking the source Realm, which could race with things that invalidated the source Realm.

To fix this, switch to copying the required data to a temporary Transaction owned by the notifier while still on the source thread. This increases the amount of work done on the source thread to create a notifier (as it has to create a new Transaction each time), but eliminates the need to hold the lock while parsing the transaction logs for new notifiers, so it may turn out to be a net reduction in main-thread blockage.

Fixes #3761.

Newly created notifiers copied their Query from the source Realm on the worker
thread without locking the source Realm, which could race with things that
invalidated the source Realm.

To fix this, switch to copying the required data to a temporary Transaction
owned by the notifier while still on the source thread. This increases the
amount of work done on the source thread to create a notifier (as it has to
create a new Transaction each time), but eliminates the need to hold the lock
while parsing the transaction logs for new notifiers, so it may turn out to be
a net reduction in main-thread blockage.
@tgoyne tgoyne force-pushed the tg/notifier-invalid-table-ref branch from 7fb5488 to 16add52 Compare December 18, 2020 03:05
@finnschiermer
Copy link
Contributor

Likely also fixes realm/realm-swift#6767 and realm/realm-swift#6916

@finnschiermer
Copy link
Contributor

finnschiermer commented Dec 18, 2020

@tgoyne Any possible connection to realm/realm-java#7100 in your opinion ?

Same question for realm/realm-java#7145 ? (I note it has "run_async_notifiers" in the stacktrace)

auto& self = Realm::Internal::get_coordinator(*notifier->get_realm());
{
util::CheckedLockGuard lock(self.m_notifier_mutex);
self.pin_version(version);
if (!self.m_async_error)
notifier->attach_to(notifier->get_realm()->duplicate());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is the core of the fix.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this ended up being the only change actually needed to fix the bug. The changes in run_async_notifiers() are left over from a different attempt at fixing the bug that failed to fix it but did bring a functional benefit (of not running new notifiers with the lock held).

@tgoyne
Copy link
Member Author

tgoyne commented Dec 18, 2020

realm/realm-java#7145 probably isn't related to this; a data race leading to the Query on the background thread having some invalid data could explain the crash, but AFAICT the racey read doesn't access anything mutated after the last synchronization point and I don't think this bug could lead to a use-after-free.

realm/realm-java#7100 may be the same bug in a different place. Calling freeze() from a thread other than the object's thread is invalid, but Results::freeze() doesn't check the thread. Cocoa indirectly checks the thread before calling it and Java appears not to (although it's very possible I'm just failing to find where it does) and so is letting the user do something unsafe.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

NoSuchTable thrown from import_copy_of()
3 participants