As an optimisation, on load of a weak reference we check if the object
has already been deallocated and, if so, decrement the weak reference
count and zero the pointer to the weak reference structure so that the
next check is faster and doesn't need to hold locks for as long.
Unfortunately, the prior implementation of this instead decremented the
weak reference count and then only zeroed the pointer if the reference
count reached zero. This meant that loading the same __weak pointer
twice after the pointed-to object had been deallocated would decrement
the reference count twice.
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.
These most likely led to some intermittent failures in weak references.
The `objc_moveWeak` and `objc_copyWeak` functions were assuming that the
target may contain valid data, but the spec for these says that it may
be uninitialised data. We were reading uninitialised data and then
seeing if it happened to be a valid object. Most of the time it was
likely to be nil, so this wasn't an easily reproduceable problem...
I believe this is the correct fix for PR #95.
Fixes#95
We weren't correctly sign-extending the value being compared, which was
resulting in objects not being deallocated. For some reason, this only
appeared on Windows, even though the code looked wrong on all platforms.
This cleans up handling of objects that are not reference counted and
makes their interactions with ARC more consistent. We should probably
generalise this somewhat - it currently special cases NSConstantString
and NSGlobalBlock, but it would be nice to have an API for constant
objects.
* use fiber local storage if NO_PTHREADS is defined
* use critical sections instead of mutexes
Contributing-author: Ben Viglietta <benvi@microsoft.com>
Weak refs were being left as dangling pointers after being deleted. The
load that caused the deallocation would return nil, but then the next
one would dereference a dangling pointer.
Fixes a bug introduced (replacing a similar bug) in the last rewrite of
objc_moveWeak. This version should now be correct.
objc_copyWeak was implemented in a naive way, which had a lot more
overhead than required.
Rather than tracking all of the locations of weak pointers, keep a weak
refcount. This should also make it easier to add finer-grained locking to weak
references.
We were not correctly checking that the object being assigned had a
reference count in the object header. We're also now avoiding assigning
small objects to the weak reference table, which is quite important as
they have no destructor.
Fixes#12
the table incorrectly, causing objects inserted at offsets due to hash
collisions to fail to be moved up and then fail to be found later.
Test by Eric Wasylishen!
- Make objc_retain() check for stack blocks and implicitly copy them. This fixes the case where a block pointer is stored in an object-typed variable and is assigned.
- Tweak objc_retainAutoreleaseReturnValue() so that the ARC optimiser doesn't detect that the body looks like a call to objc_retainAutoreleaseReturnValue() and replace it with an infinitely recursive call.
The second fix now means that arc.m will compile with clang without producing a function that calls itself.