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.
main
David Chisnall 7 years ago
parent 066a4e65a9
commit 336d8a828c

@ -629,9 +629,21 @@ namespace {
struct WeakRef struct WeakRef
{ {
void *isa = &weakref_class; void *isa = &weakref_class;
id obj = nullptr; id object;
size_t weak_count = 1; struct
WeakRef(id o) : obj(o) {} {
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> template<typename T>
@ -709,7 +721,7 @@ static BOOL loadWeakPointer(id *addr, id *obj, WeakRef **ref)
if (classForObject(oldObj) == (Class)&weakref_class) if (classForObject(oldObj) == (Class)&weakref_class)
{ {
*ref = (WeakRef*)oldObj; *ref = (WeakRef*)oldObj;
*obj = (*ref)->obj; *obj = (*ref)->obj();
return YES; return YES;
} }
*ref = NULL; *ref = NULL;
@ -723,7 +735,7 @@ static inline BOOL weakRefRelease(WeakRef *ref)
ref->weak_count--; ref->weak_count--;
if (ref->weak_count == 0) if (ref->weak_count == 0)
{ {
weakRefs().erase(ref->obj); weakRefs().erase(ref->object);
delete ref; delete ref;
return YES; return YES;
} }
@ -786,7 +798,7 @@ WeakRef *incrementWeakRefCount(id obj)
} }
else else
{ {
assert(ref->obj == obj); assert(ref->obj() == obj);
ref->weak_count++; ref->weak_count++;
} }
return ref; 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 // accesses from loading from this. This must be done after
// removing the ref from the table, because the compare operation // removing the ref from the table, because the compare operation
// tests the obj field. // tests the obj field.
oldRef->obj = nil; oldRef->isDeleted = true;
// If the weak reference count is zero, then we should have // If the weak reference count is zero, then we should have
// already removed this. // already removed this.
assert(oldRef->weak_count > 0); assert(oldRef->weak_count > 0);

Loading…
Cancel
Save