Fix test failure.
This bug is also present in the original version:
When removing a WeakRef from the map, we use its obj field to find the
key, but the obj field has already been zeroed by this point and so we
end up leaving dangling pointers in the map.
@@ -629,9 +629,21 @@ namespace {
struct WeakRef
{
void *isa = &weakref_class;
- id obj = nullptr;
- size_t weak_count = 1;
- WeakRef(id o) : obj(o) {}
+ id object;
+ struct
+ {
+ size_t weak_count:((sizeof(size_t) * 8) - 1);
+ bool isDeleted:1;
+ };
+ id obj()
+ {
+ if (isDeleted)
+ {
+ return nil;
+ }
+ return object;
+ }
+ WeakRef(id o) : object(o), weak_count(1), isDeleted(false) {}
};
template<typename T>
@@ -709,7 +721,7 @@ static BOOL loadWeakPointer(id *addr, id *obj, WeakRef **ref)
if (classForObject(oldObj) == (Class)&weakref_class)
{
*ref = (WeakRef*)oldObj;
- *obj = (*ref)->obj;
+ *obj = (*ref)->obj();
return YES;
}
*ref = NULL;
@@ -723,7 +735,7 @@ static inline BOOL weakRefRelease(WeakRef *ref)
ref->weak_count--;
if (ref->weak_count == 0)
{
- weakRefs().erase(ref->obj);
+ weakRefs().erase(ref->object);
delete ref;
return YES;
}
@@ -786,7 +798,7 @@ WeakRef *incrementWeakRefCount(id obj)
}
else
{
- assert(ref->obj == obj);
+ assert(ref->obj() == obj);
ref->weak_count++;
}
return ref;
@@ -862,7 +874,7 @@ extern "C" OBJC_PUBLIC BOOL objc_delete_weak_refs(id obj)
// accesses from loading from this. This must be done after
// removing the ref from the table, because the compare operation
// tests the obj field.
- oldRef->obj = nil;
+ oldRef->isDeleted = true;
// If the weak reference count is zero, then we should have
// already removed this.
assert(oldRef->weak_count > 0);
