Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions selector_table.cc
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,15 @@ extern "C" PRIVATE SEL objc_register_selector(SEL aSel)
return registered;
}
assert(!(aSel->types && (strstr(aSel->types, "@\"") != nullptr)));
// Acquire the runtime lock before the selector table lock. Registering a
// new selector resizes the dtables (objc_resize_dtables), which takes the
// runtime lock, while the class loader (__objc_load) takes the runtime lock
// first and then registers selectors. Acquiring the two in a consistent
// runtime-before-table order avoids a lock-order inversion
// (gnustep/libobjc2#391). Holding the runtime lock for the whole
// registration also keeps the new selector's index (the selector_list size)
// and the matching dtable resize atomic with respect to other resizes.
LOCK_RUNTIME_FOR_SCOPE();
LockGuard g{selector_table_lock};
register_selector_locked(aSel);
return aSel;
Expand All @@ -463,6 +472,9 @@ SEL objc_register_selector_copy(UnregisteredSelector &aSel, BOOL copyArgs)
{
return copy;
}
// Runtime lock before the selector table lock, for the duration of the
// registration; see objc_register_selector above and gnustep/libobjc2#391.
LOCK_RUNTIME_FOR_SCOPE();
LockGuard g{selector_table_lock};
copy = selector_lookup(aSel.name, aSel.types);
if (nullptr != copy && selector_identical(aSel, copy))
Expand Down
Loading