Why does ARC only sometimes retain a __block out pointer? - objective-c

1) Why does this retain its __block var:
{
void (^blockWithOutPointer)(NSObject * __autoreleasing *) = ^(NSObject * __autoreleasing * outPointer) {
*outPointer = [NSObject new];
};
NSObject * __block blockVar1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// prints non-nil. WHY????
});
blockWithOutPointer(&blockVar1);
}
2) But this doesn't?
void (^blockWithOutPointerThatDispatchesLater)(NSObject * __autoreleasing *,
dispatch_block_t) = ^(NSObject * __autoreleasing * outPointer,
dispatch_block_t block) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
block);
*outPointer = [NSObject new];
};
{
NSObject * __block blockVar2;
blockWithOutPointerThatDispatchesLater(&blockVar2,
^{
NSLog(#"blockVar2: %#",
blockVar2);
});
// prints nil, which is expected.
}
3) If I instead use an __autoreleasing variable as my out pointer destination, and then assign that variable to my __block pointer, everything works fine.
{
NSObject * __autoreleasing autoreleasingVar;
NSObject * __block blockVar3;
blockWithOutPointerThatDispatchesLater(&autoreleasingVar,
^{
NSLog(#"blockVar3: %#",
blockVar3);
});
blockVar3 = autoreleasingVar;
// prints non-nil, which is expected.
}
I've read CRD's answer about ARC pointer-to-pointer issues, it makes sense that #2 would print nil because ARC assumes that blockVar2 is __autoreleasing, and doesn't retain its value. Thus, in #3, when we assign autoreleasingVar to blockVar3, ARC properly retains the value. However, there is no such assignment for #1. Why does #1 retain its value?
Even more amazingly, #1 is unaffected if I wrap the out-pointer assignment in an #autoreleasepool:
{
void (^blockWithOutPointer)(NSObject * __autoreleasing *) = ^(NSObject * __autoreleasing * outPointer) {
#autoreleasepool {
*outPointer = [NSObject new];
}
};
NSObject * __block blockVar1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// still prints non-nil. WHY???
});
blockWithOutPointer(&blockVar1);
}
Whereas #3 crashes, as expected since the #autoreleasepool released the out-pointer's object, and I guess ARC doesn't set __autoreleasing variables to nil.
void (^blockWithOutPointerThatDispatchesLater)(NSObject * __autoreleasing *,
dispatch_block_t) = ^(NSObject * __autoreleasing * outPointer,
dispatch_block_t block) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
block);
#autoreleasepool {
*outPointer = [NSObject new];
}
};
{
NSObject * __autoreleasing autoreleasingVar;
NSObject * __block blockVar3;
blockWithOutPointerThatDispatchesLater(&autoreleasingVar,
^{
NSLog(#"blockVar3: %#",
blockVar3);
// crashes on the NSLog!
});
blockVar3 = autoreleasingVar;
}
I filed a radar about this.

You have discovered a "feature" of the block implementation and (at least for cases 1 & 2, I haven't checked further) it is nothing to do with __autoreleasing per se.
First let's look at your case 1. You seem surprised this prints a non-nil value. It works exactly as expected:
blockWithOutPointer(&blockVar1); executes, assigning a value to blockVar1; then
the block ^{ NSLog(#"blockVar1: %#", blockVar1); } is executed by GCD and the stored by (1) is printed.
(Note: You can removed the __autoreleasing qualifiers and it will work the same as this is the inferred mode for pass-by-writeback parameters.)
Now your case 2. This is where you hit the "feature":
In Objective-C objects are heap allocated; and
Objective-C blocks are objects; so
Ergo blocks are heap allocated...
Except when they are not...
As an optimisation the block specification allows blocks and their captured __block variables to be stack allocated and only moved onto the heap when their lifetime needs to be longer than the stack frame are in.
As an optimisation it should (a) be essentially invisible to the programmer - apart from any perf benefit and (b) not change the semantics in anyway. However Apple decided to initially introduce it as a "programmer assisted optimisation" and have then slowly improved matters.
The behaviour of your case 2 is all down to when the block and __block variable get copied onto the heap. Let's look at the code:
NSObject * __block blockVar2;
This declares blockVar2 to have __block storage duration, which allows a block to alter the value of this locally declared variable. At this point the compiler does not know whether a block may access it, in which case blockVar2 will need to be on the heap, or whether it won't, in which case it may be on the stack.
The compiler decides it prefers the stack and allocates blockVar2 there.
blockWithOutPointerThatDispatchesLater(&blockVar2,
Now the compiler needs to pass the address of blockVar2 as the first argument, the variable is currently on the stack, and the compiler emits code to calculate its address. That address is on the stack.
^{
NSLog(#"blockVar2: %#",
blockVar2);
});
Now the compiler gets to the second argument. It sees the block, that the block accesses blockVar2, and that blockVar2 is qualified by __block so it must capture the variable itself and not the variables value.
The compiler decides the block should go on the heap. For this to work it needs to migrate blockVar2 onto the heap, so it does that along with its current value nil...
Oops!
The first argument is the address of the original blockVar2 on the stack, while the second argument is a block which in turn references the cloned blockVar2 on the heap.
When the code is executed blockWithOutPointerThatDispatchesLater() allocates an object and stores its address in the stack blockVar2; then GCD executes the delayed block which prints of the value of the heap blockVar2, which is nil.
A “Fix”
Just change your code to:
NSObject * __block blockVar2;
dispatch_block_t afterBlock = ^{
NSLog(#"blockVar2: %#", blockVar2);
};
blockWithOutPointerThatDispatchesLater(&blockVar2, afterBlock);
i.e. pre-calculate the second argument expression. Now the compiler sees the block before it sees &blockVar2, moves the block and blockVar2 to the heap, and the value generated for &blockVar2 is the address of the heap version of blockVar2.
Expanded Conclusion: Bug or Feature?
The original answer simply stated this is clearly a bug, not a feature, and suggest you file a bug report, noting it's been reported before but another report won't harm.
However that might be a little unfair, yes it is a bug, the question is what the bug actually is. Consider:
In (Objective-)C variables, allocated on the stack or statically, and allocated dynamic memory blocks do not move during their lifetime.
Compiler optimisations in general should not alter the meaning or correctness of a program.
Apple has implemented a compiler optimisation – storing blocks and captured __block variables on the stack – in a way which can move __block attributed variables during their lifetime and in doing so the meaning and correctness of a program can be altered.
The result is a simple re-ordering of program statements in a way which should not alter program meaning or correctness in fact does. This is bad!
Given the history of the optimisation, as implemented by Apple, which by-design relied on programmer assistance (though it has since been made more automatic) for its correctness this could simply be seen as another “feature” of the chosen implementation.
Recommendation
Never, ever, apply the address-of (&) operator to a variable with __block storage duration. If may work if you do, but it just as easily may not.
If you need to use a __block variable as a pass-by-writeback argument then copy it to a local temporary first, make the call, and finally copy it back again.
HTH

There's probably a misconception in 1):
If a variable will be imported into a block, which is marked with __block the compiler generates a helper struct containing various fields and the variable corresponding to the given source. That is, there's no pointer blockVar1, instead there's a whole struct instead.
If a block imports this variable and needs to be copied (for example, when asynchronously submitted) it also "moves" this helper struct onto the heap before "moving" the block itself onto the heap.
This statement
NSObject * __block blockVar1;
will initialise the helper struct which embeds the actual variable and initialises it to nil. The corresponding address of the variable points into the stack.
When the compiler parses this statement:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(1 * NSEC_PER_SEC)),
dispatch_get_main_queue(),
^{
NSLog(#"blockVar1: %#",
blockVar1);
// prints non-nil. WHY????
});
The compiler generates code for the compound statement, specifically it creates a struct representing the block which initially exists on the stack, too. Since this block requires to be moved to the heap before executing dispatch_async, it also moves the helper struct onto the heap in subsequently generated code.
Additionally, since the imported variable is a NSObject pointer, it also assigns function pointers (located in the helper struct) which "keep" and "dispose" the object, which will be called when the helper struct is "moved" to the heap, respectively when it is destroyed.
When you finally execute this statement
blockWithOutPointer(&blockVar1);
the address of the variable has already been changed: the variable is now located on the heap (since the helper struct has been "moved" to the heap") and exists as long as the block.
Now, to the point where you declare (and define) the following block:
void (^blockWithOutPointer)(NSObject * __autoreleasing *)
What causes gripes here is the __autoreleasing modifier, specifically Storage duration of __autoreleasing objects:
That is, __autoreleasing can only be applied to variables with automatic storage duration.
Edit:
This would assume that the given variable is on the stack. However, it is located on the heap. Thus, your program is illformed and the behaviour is undefined.
Regarding the __autoreleasing storage qualifier, the code sample 1) is correct (the _autoreleasing storage qualifier refers to a temporary that is created when passing the variable as a parameter, see comments below).
What I've said previously above should be correct, and what the user is experiencing is thus expected.
For further reference see: http://clang.llvm.org/docs/Block-ABI-Apple.html
However:
There's still a subtle potential issue with a "data race": the statement
blockWithOutPointer(&blockVar1);
will modify a pointer variable which is located on the heap, while executing on the current thread. Later, on the main thread the same variable will be read. Unless current thread equals main thread, this exhibits a classic data race.
While this is not the question and no a complete answer - it shows, how quickly such code becomes more complex than desired and I would recommend to strive for simpler, comprehensible code.
End Edit
I haven't analysed the other code samples
- but at the first glance it seems, using __autoreleasing leads also to an illformed program.

Related

Why did Apple design __block for write auto var in block?

We can read auto var in block:
int aVar = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(#"theVar==%d", aVar);
});
But can not write:
int aVar = 1;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
aVar = 2;
NSLog(#"theVar==%d", aVar);
});
Xcode showed:Variable is not assignable (missing __block type specifier).
I know that when there is no __block,auto var pass to block as a copy so it's readonly.And with __block its address pass to block.
But I can't understand why Apple must design as this?Just copy address to block is not OK?Is there any potential problem If auto var in block without __block is writeable?
It's not as simple as "with __block its address pass to block", because a block that captures the variable can outlive the scope that it's created in, and a local variable of automatic storage duration would become invalid at the end of the scope, so just capturing its address won't work.
A variable declared with __block actually involves a hidden structure behind the scenes, which can be "moved" from the stack to the heap if necessary so it can outlive the scope it was created in, and there are additional hidden fields that the compiler generates behind the scenes to allow someone accessing the variable to figure out the real location of the variable (stack or heap) at that time. Also, the blocks need to manage the memory of the copy of the variable on the heap. So defining a __block variable requires additional storage compared to the variable itself, and accessing a __block variable requires more levels of indirection and more memory management logic for the blocks involved. This additional complication should only be used if needed; therefore, variables captured by blocks are not __block by default.

Double pointer as Objective-C block parameter

Is it possible (and if so, safe) to create/use a block which takes a double pointer as an argument?
For instance:
- (void)methodWithBlock:(void (^)(NSError **error))block;
Additional context, research, and questions:
I'm using ARC.
When I declare the method above and attempt to call it, XCode autocompletes my method invocation as follows: [self methodWithBlock:^(NSError *__autoreleasing *error) {}];
What does __autoreleasing mean here and why is it being added? I presume it has something to do with ARC.
If this is possible and safe, can the pointer still be dereferenced in the block as it would be anywhere else?
In general, what are the important differences between doing what I'm describing, and simply passing a double pointer as a method parameter (e.g. - (void)methodWithDoublePointer:(NSError **)error;)? What special considerations, if any, should be taken into account (again assuming this is possible at all)?
yes, pointers are always just pointers. you only need to make sure you dereference it before sending it a message (assuming objc object).
Also be aware that the pointer may be nil. always check it before trying to dereference it or what have you.
As #verec mentioned if you are using ARC you should declare the parameter as __autoreleasing
according to the docs
__autoreleasing is used to denote arguments that are passed by reference (id *) and are autoreleased on return.
remember id is a pointer to an object so that is saying object**
there is no difference between passing pointers to pointers to methods or blocks.
The answers are both Yes & No...
At a base level passing pointers to pointers to blocks is no different than passing them to methods; and, with the usual proviso that your pointers must be valid, is perfectly OK.
However that __autoreleasing is very significant here and is tied up with ARC and pass-by-writeback. Whether using the block will work as expected will be dependent on context as the compiler often uses hidden variables when passing parameters of type NSError * __autoreleasing * as part of the pass-by-writeback implementation.
If pass-by-writeback is not what you need, or is unsuitable, you may wish to declare you block as taking a different type, such as NSError * __strong *. Read this answer which explains what happens under the hood, that should help you decide whether in your context the block declaration is good.
In summary (a) declaring the block is fine, but (b) you need to understand how it may be called and may need to change the signature.
warning: untested
For the sake of argument, let's start with:
typedef NSError * NSErrorPtr ;
- (void) foo: (NSErrorPtr *) errPtr {
*errorPtr = [NSError new] ;
}
errPtr isn't declared either __weak nor __strong.
So, according to ARC, even though its contents is allocated within foo the responsibility for releasing it has to reside somewhere.
Where?
Note that this not a property of double pointers per se. But of your pattern of allocation.
consider:
int ** arrayOfarrayOfInts = {
{1, 2, 3, 4}
, {5, 6, 7, 8}
} ;
- (void) incrementElement: (int **) elem {
++(**elem) ;
}
- (void) bumpFirstColByOne {
for (int i = 0 ; i < 2 ; ++ i) {
int * arrayOfInt = arrayOfarrayOfInts[i] ;
int ** second = &arrayOfInt[0] ;
[self incrementElement: second] ;
}
}
No __autoreleasing needed here because no allocation is taking place ...

Lifecycle of blocks in Objective-C

MyBlock getBlocks()
{
MyBlock myBlock = ^{
NSLog(#"Hello World!");
};
return myBlock;
}
int main(int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
MyBlock myBlock = getBlocks();
myBlock();
[pool drain];
return 0;
}
Why does this snippet of code work? myBlock should be destroyed.
By the way, this snippet also works:
NSObject *obj = [[NSObject alloc] init];
NSLog(#"%ld", [obj retainCount]);
MyBlock myBlock = ^{
NSLog(#"Hello World!");
NSLog(#"%ld", [obj retainCount]);
};
[obj release];
but [obj retainCount] in block prints 1 instead 2, why?
Blocks can be allocated on the stack for performance reasons and only migrate away to the heap when you copy them. If your block doesn't capture any values, the compiler can also turn it into a global block whose memory exists in some fixed static memory location.
Since your getBlocks block doesn't capture anything, it is a global block and its memory can't be disposed. It doesn't have reference counting semantics and retain/release won't do anything. Its reference will always be valid and you'll always be able to call it.
If the block in getBlocks did capture some values, it would be a local stack-allocated block, and the method would be returning a reference to that stack memory, which is of course very dangerous. The code may even still work in this case and you'd be able to call it even though it is sitting in unowned stack memory (as long as that memory hasn't been trashed by somebody else by the time you call the block).
I believe your second example is also demonstrating the side effects of a stack-allocated block. The objects captured by a stack-allocated block will only be retained when the block is actually copied to the heap for the first time. This doesn't happen in your code so obj isn't retained by the block.
This does mean that after calling [obj release] in your example, the block is now capturing a dangling pointer. Using ARC will fix all these messy details for you.
See How blocks are implemented (and the consequences) (Cocoa With Love) for more details.
Edit: Also, obligatory link to when to use retainCount
Why does this snippet of code work?
The first snipped is working because the block implementation has no reference to the surrounding scope, and it's therefore configured by clang as a global block. This causes the block not to be on the stack as it would normally be.
myBlock should be destroyed.
Stack frames (and their local variable) don't get destroyed. Their memory is made available for further allocation. Anyway, due to the simplicity of your example, you're getting a global block which doesn't live on the stack frame.
If you were making any reference to the surrounding scope you would have had a stack-based block and myBlock would have been a dangling pointer to an on-owned memory location, likely leading to a crash.
[obj retainCount] in block prints 1 instead 2, why?
Sounds reasonable.
You are allocating an object (retain count: 1), the block is retaining it (retain count: 2), you are releasing it (retain count: 1), the block is eventually executed (retain count still 1).
As a general note, anyway, don't rely upon retainCount when reasoning about memory. The memory management process has a lot going on under the hood, and you cannot definitely say anything only by looking at the value of retainCount, due to internal details of the implementation that you cannot possibly take into account. More on the subject here: http://whentouseretaincount.com/

NSDictionary of Blocks as argument cause overflow

I understand blocks are objective c objects and can be put in NSDictionary directly without Block_copy when using ARC. But I got EXC_BAD_ACCESS error with this code:
- (void)viewDidLoad
{
[super viewDidLoad];
[self method1:^(BOOL result){
NSLog(#"method1WithBlock finished %d", result);
}];
}
- (void) method1:(void (^)(BOOL))finish{
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:^(NSData *rcb){
finish(YES);
}, #"success",
^(NSError *error){
finish(NO);
}, #"failure", nil];
[self method2:dict];
}
- (void) method2:(NSDictionary *)dict{
void (^success)(NSData *rcb) = [dict objectForKey:#"success"];
success(nil);
}
If I change method1: to this, no error raised.
- (void) method1:(void (^)(BOOL))finish{
void (^success)(NSData *) = ^(NSData *rcb){
finish(YES);
};
void (^failure)(NSError *error) = ^(NSError *error){
finish(NO);
};
NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:success, #"success",
failure, #"failure", nil];
[self method2:dict];
}
Can anybody explain why I have to use automatic variables to store the blocks before putting them to dictionary ?
I am using iOS SDK 6.1.
According to the "Transitioning to ARC Release Notes", you have to copy a block stored
in a dictionary (emphasis mine):
Blocks “just work” when you pass blocks up the stack in ARC mode, such
as in a return. You don’t have to call Block Copy any more.
You still need to use [^{} copy] when passing “down” the stack into
arrayWithObjects: and other methods that do a retain.
The second method works "by chance" because success and failure are a
__NSGlobalBlock__ and not a "stack based block" that needs to be copied to the heap.
I understand blocks are objective c objects and can be put in NSDictionary directly without Block_copy when using ARC.
No, they're not common objects. When you create a block it is on the stack, and it doesn't matter of what is it's retain count, when you exit form the function it will be popped from the stack. Copy it to make it stay alive.
You must copy blocks before passing them to a method when 1) the block will be stored for longer than the duration of the call, and 2) the parameter you are passing it to is a normal object pointer type (i.e. id or NSObject *) instead of a block type.
This is the case for your call. dictionaryWithObjectsAndKeys: stores the argument in the resulting dictionary, and it simply expects normal object pointer arguments (of type id), and does not know whether you are passing blocks or not.
The reason for the second condition I said is because if the method parameter already takes a block type (e.g. for any completion handler parameters), then that method is already aware of the special memory management requirements of blocks, and therefore will take responsibility for copying the block if it needs to store it. In that case the caller doesn't need to worry about it. However, in your case, you are passing it to a general method that doesn't know it's getting a block, and thus doesn't know to copy it. So the caller must do it.
Can anybody explain why I have to use automatic variables to store the
blocks before putting them to dictionary ?
About this, your second example happens to work because recent versions of the ARC compiler is super conservative about blocks and inserts copies whenever you assign it to a block type variable. However, this is not guaranteed by the ARC specification, and is not guaranteed to work in the future, or in another compiler. You should not rely on this behavior.

How can code inside an Objective-C block reference the block object itself?

self is merely a captured variable inside a block and doesn't reference the block itself, so how does a block reference itself without having an explicit captured variable for that purpose?
__block void(^strawberryFields)();
strawberryFields = [^{ strawberryFields(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
strawberryFields);
you use the __block because the block will make a copy of the value of strawberryFields when the block is created which will be before the assignment.
you also must copy the block prior to any other copy operation or else you'll end up with a block that references the on-stack original version.
note that the above code leaks the block. Somewhere, there needs to be a release of that block to balance the copy.
I found this pattern to work and stable for ARC (automatic reference counting), both in Debug and Release builds.
-(void) someMethod
{
// declare a __block variable to use inside the block itself for its recursive phase.
void __block (^myBlock_recurse)();
// define the block
void (^myBlock)() = ^{
// ... do stuff ...
myBlock_recurse(); // looks like calling another block, but not really.
};
// kickstart the block
myBlock_recurse = myBlock; // initialize the alias
myBlock(); // starts the block
}
Initially I tried just putting a __block modifier to myBlock and use that variable directly to recurse within the block's implementation. That works on the ARC Debug build but breaks with an EXC_BAD_ACCESS on the Release build. On the other hand removing the __block modifier raises a "variable not defined when captured by block" warning (and I was reluctant to run it and test).
I have never tried this before and not 100% sure it's useful, if valid, but for example:
typedef void (^BasicBlock)(void);
__block BasicBlock testBlock;
testBlock = ^{NSLog(#"Testing %p", &testBlock);};
testBlock();
You probably have declare the variable with __block to prevent self-retain cycle.
The block needs some way to nil out its own reference. Typically it is done by storing the block in a property of the class.
Sometimes you can prefer to not use a property. Here is how you do it without a property:
__weak id weakSelf = self;
__block id block = ^{
if(weakSelf) {
// .. do whatever
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
}
else {
block = nil;
}
};
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC), dispatch_get_main_queue(), block);
The key thing to keep in mind is that all code paths must lead to a block = nil. We do that here by calling the block every 5 seconds until weakSelf turns nil.
Note that in ARC, it's a little different -- __block object pointer variables are by default retained in ARC, unlike in MRC. Thus, it will cause a retain cycle. It is necessary for the block to capture a weak reference to itself (using __weak) in order to not have a retain cycle.
However, we still need a strong reference to the block somewhere. If there are no strong references, the block (which is on the heap since it's copied) will be deallocated. Thus, we need two variables, one strong and one weak, and inside the block use the weak one to reference itself:
__block __weak void(^weakBlock)();
void(^myBlock)();
weakBlock = myBlock = [^{ weakBlock(); } copy];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),
myBlock);