Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object created inside scope deallocated even when used outside of scope

Update: This was fixed in iOS 6.1 DP3 SDK.

I've tracked down a use-after-deallocated crash when building with ARC using the default release build configuration (debug seems to work fine). The problem occurs when creating an object inside an if-scope with a non-constant condition, assigning it to a variable from outside the scope and then only referencing the variable using Objective-C array or dictionary literals.

Here is the smallest reproducible case I've managed to find:

void test(BOOL arg)
{
    id obj = nil;

    if (arg) {
        obj = [NSObject new];
    }

    // obj already deallocated here
    @[obj];

    // but using NSArray works
    //[NSArray arrayWithObject:obj];

    // @[obj] works if obj is referenced i.e. by NSLog print out
    //NSLog(@"%@", obj);
}

int main(int argc, const char * argv[])
{
    @autoreleasepool {
        test(YES);
    }
    return 0;
}

When I build and run this with zombie objects enabled I get this error message:

-[NSObject retain]: message sent to deallocated instance 0x100109100

As I commented in the code it works fine if obj is referenced in some other way, like with NSLog or using NSArray instead. Have I misunderstood how objects are released with ARC and scopes or is this a optimization bug in LLVM or Clang?

I'm using Xcode 4.5.2 with clang version 4.1 (tags/Apple/clang-421.11.66) (based on LLVM 3.1svn). I can reproduce it when building for x86 64 bit for iOS simulator and Mac OS X and I'm quite sure the same problem occurs when building for ARM as the issue was first found when running release build on an iPhone.

I have filed and bug report to Apple and created an open radar report.

What, if anything, am I missing?

Update, did some more experiments:

As Gabro pointed out the compiler translates @[] to a [NSArray arrayWithObjects:count:] statement so I did some tests:

// works
id a[] = {obj};
[NSArray arrayWithObjects:a count:1];

// does not work
const id *b = (id[]){obj};
[NSArray arrayWithObjects:b count:1];

// does not work
[NSArray arrayWithObjects:(id[]){obj} count:1];

So my guess is that this happens when combining ARC and anonymous C arrays.

like image 270
Mattias Wadman Avatar asked Dec 03 '12 16:12

Mattias Wadman


People also ask

Which of the following is the cause for an object being out of scope?

Any local variable defined within a frame will go out of scope once the program exits that frame.

When object are created on stack it gets automatically destroyed once it goes out of scope?

Object allocated on the stack are destroyed but object allocated on the heap using operator new not. You have to destroy them manually or wrap them to unique_ptr.

When an object is destroyed or goes out of scope What type?

The destructor is only one way to destroy the object create by constructor. Hence destructor can-not be overloaded. Destructor neither requires any argument nor returns any value. It is automatically called when object goes out of scope.

What happens when a variable goes out of scope?

A variable declared inside a function has a function scope. It has been allocated memory when the function is called and once the function returns something the function execution ends and with it the variable goes out of scope i.e. it gets deleted from the memory.


1 Answers

You're not missing anything. It's a compiler bug.

like image 87
rob mayoff Avatar answered Oct 25 '22 04:10

rob mayoff