From 0cec0f6e13352a301f7eab74889aa4f14142595b Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Tue, 13 Oct 2026 11:30:54 +0100 Subject: [PATCH] Move hidden-class lock initialisation earlier. This is now done when the hidden class is created, *before* it's added to any global structure. This ensures that the lock is always available. Fixes #424 --- associate.mm | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/associate.mm b/associate.mm index 9cee7b8f..7c1a3943 100644 --- a/associate.mm +++ b/associate.mm @@ -216,6 +216,11 @@ static Class allocateHiddenClass(Class superclass) newClass->dtable = uninstalled_dtable; newClass->instance_size = superclass->instance_size; + // Initialise the lock *before* this is globally reachable via any path. + // This would ideally belong in `initHiddenClassForObject`, but it's also + // possible to find the class after this point by traversing the class + // hierarchy and paths after that may attempt to acquire the lock. + INIT_LOCK(static_cast(object_getIndexedIvars(reinterpret_cast(newClass)))->lock); LOCK_RUNTIME_FOR_SCOPE(); newClass->sibling_class = superclass->subclass_list; superclass->subclass_list = (Class)newClass; @@ -308,8 +313,6 @@ static void deallocHiddenClass(id obj, SEL _cmd) if (NULL == hiddenClass) { hiddenClass = initHiddenClassForObject(object); - struct reference_list *list = static_cast(object_getIndexedIvars(hiddenClass)); - INIT_LOCK(list->lock); } } return hiddenClass ? static_cast(object_getIndexedIvars(hiddenClass)) : nullptr; @@ -419,8 +422,6 @@ static Class hiddenClassForObject(id object) if (NULL == hiddenClass) { hiddenClass = initHiddenClassForObject(object); - struct reference_list *list = static_cast(object_getIndexedIvars(hiddenClass)); - INIT_LOCK(list->lock); } } return hiddenClass; @@ -445,8 +446,6 @@ id object_clone_np(id object) referenceListForObject(object, YES); id newInstance = class_createInstance(object->isa, 0); Class hiddenClass = initHiddenClassForObject(newInstance); - struct reference_list *list = static_cast(object_getIndexedIvars(hiddenClass)); - INIT_LOCK(list->lock); objc_setAssociatedObject(newInstance, &prototypeKey, object, OBJC_ASSOCIATION_RETAIN_NONATOMIC); return newInstance;