Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why setting object that is undergoing deallocation to weak property results in crash

Tags:

In Clang's Objective-C Automatic Reference Counting we see the following

For __weak objects, the lvalue is updated to point to the new pointee, unless the new pointee is an object currently undergoing deallocation, in which case the lvalue is updated to a null pointer. This must execute atomically with respect to other assignments to the object, to reads from the object, and to the final release of the new pointee.

In objc-weak.mm wee see the following chunk of code in weak_register_no_lock():

    if (deallocating) {     if (crashIfDeallocating) {         _objc_fatal("Cannot form weak reference to instance (%p) of "                     "class %s. It is possible that this object was "                     "over-released, or is in the process of deallocation.",                     (void*)referent, object_getClassName((id)referent));     } else {         return nil;     } } 

I set a breakpoint in my UIViewController subclass dealloc method and tried invoking [self allowsWeakReference] in lldb which resulted in NO value.

If we try to set self to weak property of another object the app will crash in accordance with the objc-weak.mm code.

The question is – why does this happen? Is the clang's specification wrong? Is is this a bug in objc implementation?


Here is a simple piece of code that will reproduce the crash:

//cc -fmodules -fobjc-arc -g crash.m -o crash @import Foundation;  @interface Foo : NSObject @end  @implementation Foo - (void)dealloc {   Foo * __weak weakSelf = self; // crashes on this line } @end  int main() {   (void)[[Foo alloc] init];   return 0; } 
like image 790
Nikita Ilyasov Avatar asked Mar 14 '16 15:03

Nikita Ilyasov


1 Answers

It's not a bug: it's obviously very intentional. It is a deviation from the spec, but it's an intentional one.

Based on the warning, it sounds like they wanted to make it easier to diagnose over-release scenarios, and catching objects that are being deallocated at the time might just be a side effect of that main goal.

They might also consider that, if you're trying to weakify self while being deallocated anyway, and you're not checking for a nil weakref (quite common - lots of block code repeatedly calls through a weakref that could go nil at any time!), you're setting yourself up for hard to debug bugs.

All that said, I'd love to see the notes behind that runtime change.

like image 60
Jeremy W. Sherman Avatar answered Sep 19 '22 11:09

Jeremy W. Sherman