Understand one edge case of block memory management in objc - ios

the code below will crash because of EXC_BAD_ACCESS
typedef void(^myBlock)(void);
- (void)viewDidLoad {
[super viewDidLoad];
NSArray *tmp = [self getBlockArray];
myBlock block = tmp[0];
block();
}
- (id)getBlockArray {
int val = 10;
//crash version
return [[NSArray alloc] initWithObjects:
^{NSLog(#"blk0:%d", val);},
^{NSLog(#"blk1:%d", val);}, nil];
//won't crash version
// return #[^{NSLog(#"block0: %d", val);}, ^{NSLog(#"block1: %d", val);}];
}
the code runs in iOS 9 with ARC enabled. And I was trying to figure out the reason that lead to crash.
by po tmp in lldb I found
(lldb) po tmp
<__NSArrayI 0x7fa0f1546330>(
<__NSMallocBlock__: 0x7fa0f15a0fd0>,
<__NSStackBlock__: 0x7fff524e2b60>
)
whereas in the won't crash version
(lldb) po tmp
<__NSArrayI 0x7f9db481e6a0>(
<__NSMallocBlock__: 0x7f9db27e09a0>,
<__NSMallocBlock__: 0x7f9db2718f50>
)
So the most possible reason I could come up with is when ARC release the NSStackBlock the crash happen. But why would so?

First, you need to understand that if you want to store a block past the scope where it's declared, you need to copy it and store the copy instead.
The reason for this because of an optimization where blocks which capture variables are initially located on the stack, rather than dynamically allocated like a regular object. (Let's ignore blocks which don't capture variables for the moment, since they can be implemented as a global instance.) So when you write a block literal, like foo = ^{ ...};, that's effectively like assigning to foo a pointer to a hidden local variable declared in that same scope, something like some_block_object_t hiddenVariable; foo = &hiddenVariable; This optimization reduces the number of object allocations in the many cases where a block is used synchronously and never outlives the scope where it was created.
Like a pointer to a local variable, if you bring the pointer outside the scope of the thing it pointed to, you have a dangling pointer, and dereferencing it leads to undefined behavior. Performing a copy on a block moves a stack to the heap if necessary, where it is memory-managed like all other Objective-C objects, and returns a pointer to the heap copy (and if the block is already a heap block or global block, it simply returns the same pointer).
Whether the particular compiler uses this optimization or not in a particular circumstance is an implementation detail, but you cannot assume anything about how it's implemented, so you must always copy if you store a block pointer in a place that will outlive the current scope (e.g. in a instance or global variable, or in a data structure that may outlive the scope). Even if you knew how it was implemented, and know that in a particular case copying is not necessary (e.g. it is a block that doesn't capture variables, or copying must already have been done), you should not rely on that, and you should still always copy when you store it in a place that will outlive the current scope, as good practice.
Passing a block as an argument to a function or method is somewhat complicated. If you pass a block pointer as an argument to a function parameter whose declared compile-time type is a block-pointer type, then that function would in turn be responsible for copying it if it were to outlive its scope. So in this case, you wouldn't need to worry about copying it, without needing to know what the function did.
If, on the other hand, you pass a block pointer as an argument to a function parameter whose declared compile-time type is a non-block object pointer type, then that function wouldn't be taking responsibility for any block copying, because for all it knows it's just a regular object, that just needs to be retained if stored in a place that outlives the current scope. In this case, if you think that the function may possibly store the value beyond the end of the call, you should copy the block before passing it, and pass the copy instead.
By the way, this is also true for any other case where a block-pointer type is assigned or converted to a regular object-pointer type; the block should be copied and the copy assigned, because anyone who gets the regular object-pointer value wouldn't be expected to do any block copying considerations.
ARC complicates the situation somewhat. The ARC specification specifies some situations where blocks are implicitly copied. For example, when storing to a variable of compile-time block-pointer type (or any other place where ARC requires a retain on a value of compile-time block-pointer type), ARC requires that the incoming value be copied instead of retained, so the programmer doesn't have to worry about explicitly copying blocks in those cases.
With the exception of retains done as part of initializing a
__strong parameter variable or reading a __weak variable, whenever
these semantics call for retaining a value of block-pointer type, it
has the effect of a Block_copy.
However, as an exception, the ARC specification does not guarantee that blocks only passed as arguments are copied.
The optimizer may remove such copies when it sees that the result is
used only as an argument to a call.
So whether to explicitly copy blocks passed as arguments to a function is still something the programmer has to consider.
Now, the ARC implementation in recent versions of Apple's Clang compiler has an undocumented feature where it will add implicit block copies to some of the places where blocks are passed as arguments, even though the ARC specification doesn't require it. ("undocumented" because I cannot find any Clang documentation to this effect.) In particular, it appears that it defensively always adds implicit copies when passing an expression of block-pointer type to a parameter of non-block object pointer type. In fact, as demonstrated by CRD, it also adds an implicit copy when converting from a block-pointer type to a regular object-pointer type, so this is the more general behavior (since it includes the argument passing case).
However, it appears that the current version of the Clang compiler does not add implicit copies when passing a value of block-pointer type as varargs. C varargs are not type-safe, and it is impossible for the caller to know what types the function expects. Arguably, if Apple wants to error on the side of safety, since there's no way of knowing what the function expects, they should add implicit copies always in this case too. However, since this whole thing is an undocumented feature anyway, I wouldn't say it's a bug. In my opinion, then programmer should never rely on blocks that are only passed as arguments being implicitly copied in the first place.

Short Answer:
You have found a compiler bug, possibly a re-introduced one, and you should report it at http://bugreport.apple.com.
Longer Answer:
This wasn't always a bug, it used to be a feature ;-) When Apple first introduced blocks they also introduced an optimisation in how they implemented them; however unlike normal compiler optimisations which are essentially transparent to the code they required programmers to sprinkle calls to a special function, block_copy(), in various places to make the optimisation work.
Over the years Apple removed the need for this, but only for programmers using ARC (though they could have done so for MRC users as well), and today the optimisation should be just that and programmers should no longer need to help the compiler along.
But you've just found a case where the compiler gets it wrong.
Technically you have a case a type loss, in this case where something known to be a block is passed as id - reducing the known type information, and in particular type loss involving the second or subsequent argument in a variable argument list. When you look at your array with po tmp you see the first value is correct, the compiler gets that one right despite there being type loss, but it fails on the next argument.
The literal syntax for an array does not rely on variadic functions and the code produced is correct. However initWithObjects: does, and it goes wrong.
Workaround:
If you add a cast to id to the second (and any subsequent) blocks then the compiler produces the correct code:
return [[NSArray alloc] initWithObjects:
^{NSLog(#"blk0:%d", val);},
(id)^{NSLog(#"blk1:%d", val);},
nil];
This appears to be sufficient to wake the compiler up.
HTH

Related

Does object need (a) `__block` modifier or (b) weak reference, when accessed from within a block in Objective-C?

In Objective-C (as of Xcode 7), the __block modifier for use with primitives is clearly explained in Stack Overflow such as here and by Apple here in the Blocks Programming Guide. Without the label, a copy of the primitive is captured and the original cannot be modified from within the block. With the label, no copy, and the original can be modified from within the block.
But for use with pointers to objects, the situation is not so well explained. Here Apple says either “a strong reference is made to self” or “a strong reference is made to the variable”. But then at the end of the page Apple says:
To override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
What does “override this behavior” mean?
Further complicating things is that some posts on Stack Overflow talking about making a weak reference when calling an object from within a block.
I am not trying to establish an object. I just want to modify an existing object’s state from within a block. I believe the block is being called synchronously, within the same thread.
Imagine:
Clicker* myClicker = [[Clicker alloc] init] ;
…
// Declare a block.
void (^myBlock)( );
// Populate the block.
myBlock = ^ void ( ) {
[myClicker click] ; // Updating some state in that object, such as incrementing a counter number or adding an element to a collection.
};
// Call `myBlock` synchronously (same thread) from some other code.
… // … invokes `myBlock` repeatedly …
My questions:
How should that code be modified with __block modifier?
How should that code be modified with weak references?
What other issues apply to an object’s state modified from within a block?
First of all, the basic point of __block is the same for all types of variables (primitive variables, object-pointer variables, and all other variables) -- __block makes the variable shared between the outside scope and the scopes of the blocks that capture it, so that an assignment (=) to the variable in one scope is seen in all other scopes.
So if you don't use __block, if you assign to an object-pointer variable to point to another object outside the block after the block is created, the block won't see the assignment to the variable, and will still see it pointing to the object it was pointing to when the block was created. Conversely, inside the block you won't be able to assign to the variable. If you do use __block, then assignments to the variable to point to another object, either inside or outside the block, will be reflected in the other scopes.
Note that mutation of objects' state has nothing to do with assignment to variables. You mutate objects' state by calling a mutating method on a pointer to the object, or you can alter a field directly using a pointer to the object using the -> syntax. Neither of these involve assigning to a variable holding the pointer to the object. On the other hand, assigning to a variable holding a pointer to an object only makes the pointer point to another object; it does not mutate any objects.
The part you are reading about strong references and "override this behavior" has to do with the separate issue of memory management behavior of blocks under MRC only. Under MRC, there is no concept of variables being __strong or __weak like in ARC. When a variable of object-pointer type is captured by a block in MRC, it is by default captured as a strong reference (the block retains it, and releases it when the block is deallocated), because that is the desired behavior most of the time. If you wanted the block to not retain the captured variable, the only way to do that was to make it __block, which not only made the variable shared between the two scopes, but also made the block not retain the variable. So the two concepts were conflated in MRC.
In ARC, whether a block captures a variable strongly or weakly depends on the captured variable being __strong or __weak (or __unsafe_unretained), and is completely orthogonal with whether the variable is __block or not. You can have object-pointer variables that are __block without being weakly captured, or weakly captured without being __block, or both weakly captured and __block if you want.
You quote the somewhat dated Blocks Programming Topics, which says:
To override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
That document dates back to the days of manual reference counting, back before ARC. In manual reference counting code you could use __block to avoid establishing a strong reference to objects referenced inside the block.
But this behavior has changed with ARC, as outlined in Transitioning to ARC Release Notes. We now use weak in those cases where we don't want to establish strong references to the objects referenced in the block. (You can use unsafe_unretained in special cases where you know the resulting dangling pointer isn't a problem.)
So, go ahead and use __block when dealing with fundamental types that you want to mutate inside the block. But when dealing with objects in blocks under ARC, the __block qualifier generally doesn't enter the discussion. The question is simply whether you want a strong reference or a weak one (or an unsafe, unretained one). And that's largely dictated by the object graph of your app, namely (a) whether you need weak/unretained reference to prevent strong reference cycle; or (b) you don't want want some asynchronously executing block to unnecessarily prolong the life of some object referenced in the block. Neither of those situations would appear to be the case here.

Blocks and messaging

The question here is more of an educational one. I began to think of this an hour ago while
flipping around a lego block (silly, I know).
A block is an object created on stack, from what I understand.
Let say A is an object, which means we can do:
[A message];
Based on that, if a block is an object, we could also do:
[block message];
Am I correct?
And when the runtime sees that, it would call:
objc_msgSend(block, #selector(message), nil);
So my question is, how can we send a block a message?
And if that is possible, I would imagine that it would also be possible to send a block a message with the arguments being blocks as well?
And, if we could call a block by doing:
block();
Does that mean we could even make a block as a message (SEL) as well, because blocks have the signature void (^)(void) which resembles that of a method?
Because if it would be possible, then the following would really surprise me:
objc_msgSend(block, #selector(block), block);
or:
objc_msgSend(block1, #selector(block2), block3);
I hope my imagination is not running a bit wild and that my understanding is not off here (correct me, if it is).
Blocks are objects only for the purposes of storage and referencing. By making them objects, blocks can be retain/release'd and can, therefore, be shoved into arrays or other collection classes. They also respond to copy.
That's about it. Even that a block starts on the stack is largely a compiler implementation detail.
When a block's code is invoked, that is not done through objc_msgSend(). If you were to read the source for the block runtime and the llvm compiler, then you'd find that:
a block is really a C structure that contains a description of the data that has been captured (so it can be cleaned up) and a pointer to a function -- to a chunk of code -- that is the executable portion of the block
the block function is a standard C function where the first argument must always be a reference to the block. The rest of the argument list is arbitrary and works just like any old C function or Objective-C method.
So, your manual calls to objc_msgSend() treat the block like any other random ObjC object and, thus, won't call the code in the block, nor, if it did (and there is SPI that can do this from a method... but, don't use it) could it pass an argument list that was fully controllable.
One aside, though of relevance.
imp_implementationWithBlock() takes a block reference and returns an IMP that can be plugged into an Objective-C class (see class_addMethod()) such that when the method is invoked, the block is called.
The implementation of imp_implementationWithBlock() takes advantage of the layout of the call site of an objective-c method vs. a block. A block is always:
blockFunc(blockRef, ...)
And an ObjC method is always:
methodFunc(selfRef, SEL, ...)
Because we want the imp_implementationWithBlock() block to always take the target object to the method as the first block parameter (i.e. the self), imp_implementationWithBlock() returns a trampoline function that when called (via objc_msgSend()):
- slides the self reference into the slot for the selector (i.e. arg 0 -> arg 1)
- finds the implementing block puts the pointer to that block into arg 0
- JMPs to the block's implementation pointer
The finds the implementing block bit is kinda interesting, but irrelevant to this question (hell, the imp_implementationWithBlock() is a bit irrelevant, too, but may be of interest).
Thanks for response. It's definitely an eye opener. The part about
blocks calling is not done thru objc_msgSend() tells me that it is
because blocks are not part of the normal object-hierachry (but coda's
mentioning of NSBlock seems to refute what I understand so far,
because NSBlock would make it part of the object-hierachy). Feel free
to take a stab at me, if my understanding is still off so far. I am
very interested in hearing more about the followings 1: the SPI and
the way (how) to call that method. 2: the underlying mechanisms of:
sliding the self reference into the slot. 3: finds the implementing
block and puts the pointer to that block into arg 0. If you have time
to share and write a bit more about those in detail, I am all ears; I
find this all very fascinating. Thanks very much in advance.
The blocks, themselves, are very much just a standard Objective-C object. A block instance contains a pointer to some executable code, any captured state, and some helpers used to copy said state from stack to heap (if requested) and cleanup the state on the block's destruction.
The block's executable code is not invoked like a method. A block has other methods -- retain, release, copy, etc... -- that can be invoked directly like any other method, but the executable code is not publicly one of those methods.
The SPI doesn't do anything special; it only works for blocks that take no arguments and it is nothing more than simply doing block().
If you want to know how the whole argument slide thing works (and how it enables tail calling through to the block), I'd suggest reading this or this. As well, the source for the blocks runtime, the objc runtime, and llvm are all available.
That includes the fun bit where the IMP grabs the block and shoves it into arg0.
Yes, blocks are objects. And yes, that means you can send messages to them.
But what message do you think a block responds to? We are not told of any messages that a block supports, other than the memory management messages retain, release, and copy. So if you send an arbitrary message to a block, chances are that it will throw a "does not recognize selector" exception (the same thing that would happen if you sent an arbitrary message to any object you don't know the interface of).
Invoking a block happens through a different mechanism than message sending, and is magic implemented by the compiler, and not exposed to the programmer otherwise.
Blocks and selectors are very different. (A selector is just an interned string, the string of the method name.) Blocks and IMPs (functions implementing methods) are somewhat similar. However, they are still different in that methods receive the receiver (self) and the selector called as special parameters, whereas blocks do not have them (the function implementing the block only receives the block itself as a hidden parameter, not accessible to the programmer).

Using C++-objects in Objective-C-blocks

I have a C++-object obj which I want to access within a block:
MyCppClass obj;
void(^myBlock)() = ^{
obj.test();
};
The problem here is that obj gets copied into the block, but I want to use a reference to the original object. I could use a pointer instead:
MyCppClass obj;
MyCppClass *objP = &obj;
void(^myBlock)() = ^{
objP->test();
};
But I think dereferencing pointers takes more time than using references. (Performance is critical, because in my project such a block is called for each pixel of a large image.)
How can I access the object within the block?
Dereferencing a pointer is faster than a function call or a C++ method call,which involves several pointer dereferences to look up the method in the class, and then an actual function call, which actually allocates memory on the stack, saves away some registers to RAM, and then does the reverse when it returns. So don't worry about performance here. If the profiler shows you that a single pointer de-reference causes performance issues, you have bigger problems, and you should probably drop down to hand-crafted assembler, and forget using C++ classes or blocks. Also, it's a very rare thing.
Use a pointer, or a C++ reference (the latter is the same under the hood, but it's harder to shoot yourself in the foot with it, and code stays more readable). Just keep in mind that this is only a solution if you are going to use the block in the same function as (or a function called by) the current function.
Because the C++ object is on the stack, it will go away, so if whoever you hand the block to copies it and calls it later, the pointer will be invalid. In the best case you will crash. In the worst case, the spot on the RAM chip that was used for that object is already in use for something else again, and you'll overwrite some other bit of memory, and cause a seemingly unrelated crash.
So, if you want to keep the block around, you'll have to do 'objP = new MyCppClass' to create the object, and later do 'delete objP' (maybe in the last call to the block, if you can detect that and don't need the object after that) to get rid of it.

Having trouble understanding Objective-C Block Documentation

I'm currently having trouble understanding the fundamentals of Obj-C blocks and the __block storage type. From the following documentation:
http://developer.apple.com/library/ios/#documentation/cocoa/Conceptual/Blocks/Articles/bxVariables.html#//apple_ref/doc/uid/TP40007502-CH6-SW6
I'm trying to understand the following paragraph and examples:
When a block is copied, it creates strong references to object variables used within the block. If you use a block within the implementation of a method:
If you access an instance variable by reference, a strong reference is made to self;
If you access an instance variable by value, a strong reference is made to the variable.
The following examples illustrate the two different situations:
dispatch_async(queue, ^{
// instanceVariable is used by reference, a strong reference is made to self
doSomethingWithObject(instanceVariable);
});
id localVariable = instanceVariable;
dispatch_async(queue, ^{
/*
localVariable is used by value, a strong reference is made to localVariable
(and not to self).
*/
doSomethingWithObject(localVariable);
});
To override this behavior for a particular object variable, you can mark it with the __block storage type modifier.
My questions:
How exactly is one example "accessed by reference" while the other one is accessed by variable? Why is localVariable "used by value?"
What does the doc mean by "a strong reference is made to self"? Which "self" is it referring to?
If I add the __block storage type to localVariable in the second example, am I wrong to assume that the block closes over the variable, so it keeps it around in heap until block is released? What other things are happening?
Thank you!
How exactly is one example "accessed by reference" while the other one is accessed by variable? Why is localVariable "used by value?"
One way to understand this is the following:
when you use a local variable in a block defined in the method, what happens is that the content of the variable is copied in some block private memory, so that it is available when the block is executed (after the method exits); in this sense we may talk of accessed "by value" (as in: the value is copied); syntactically the compiler doesn't know what the content of localVariable refers to, so its values is treated as such;
when directly accessing instanceVariable in a block defined within a method of a class, the compiler knows that we are accessing the same object that is executing the method and there is not need to copy anything, since the object has a longer lifetime than the method where the block is found; but we need to ensure that the object is still there when the block is executed, so we get a strong reference to it.
Now, as to the use of "by reference": in the first case, you get a copy of the reference to the class member: if you could change its value (but you can't, because the compiler forbids it), you were just modifying a block private copy, so the original object is not affected.
In the second case, you can modify the value of instanceVariable (like in: it was nil and you allocate an object referred through it) and this will affect the object that executed the method were the block is defined.
What does the doc mean by "a strong reference is made to self"? Which "self" is it referring to?
self is the object which is currently executing the method where the block is found. that a strong reference is made only means (in ARC parlance) that the retain count of the object is incremented (to make sure some other entity cannot cause it to be deallocated by releasing it).
If I add the __block storage type to localVariable in the second example, am I wrong to assume that the block closes over the variable, so it keeps it around in heap until block is released? What other things are happening?
Using __block makes the variable be always accessed "by reference", so you can modify them.
This is how they are handled:
__block variables live in storage that is shared between the lexical scope of the variable and all blocks and block copies declared or created within the variable’s lexical scope. Thus, the storage will survive the destruction of the stack frame if any copies of the blocks declared within the frame survive beyond the end of the frame (for example, by being enqueued somewhere for later execution). Multiple blocks in a given lexical scope can simultaneously use a shared variable.
As an optimization, block storage starts out on the stack—just like blocks themselves do. If the block is copied using Block_copy (or in Objective-C when the block is sent a copy), variables are copied to the heap. Thus, the address of a __block variable can change over time.

ARC in iOS questions

~ Will ARC always release an object the line after the last strong pointer is removed? Or is it undetermined and at some unspecified point in the future it will be released? Similarly, assuming that you don't change anything with your program, will ARC always be the same each time you run and compile your program?
~ How do you deal with handing an object off to other classes? For example, suppose we are creating a Cake object in a Bakery class. This process would probably take a long time and involve many different methods, so it may be reasonable for us to put the cake in a strong property. Now suppose we want to hand this cake object off to a customer. The customer would also probably want to have a strong pointer to it. Is this ok? Having two classes with strong pointers to the same object? Or should we nil out the Bakery's pointer as soon as we hand off?
Your code should be structured so the answer to this doesn't matter - if you want to use an object, keep a pointer to it, don't rely on ARC side effects to keep it around :) And these side effects might change with different compilers.
Two strong pointers is absolutely fine. ARC will only release the object when both pointers are pointing to something else (or nothing!)
ARC will implement the proper retains and releases at compile time. It will not behave any different than if you put them in there yourself so it will always do the same compilation and to answer your question should always behave the same. But that said it does not mean that your object will always be released immediately after the pointer is removed. Because you never call dealloc directly in any form of objective C you are only telling it that there is no reference count and that it is safe to release. This usually means that it will be released right away though.
If you pass an object from one class to another and the receiving class has a strong property associated with it and the class that passes it off eventually nils its pointer it will still have a reference count of at least 1 and will be fine.
Ok, first this answer might helpt you also a little bit: ARC equivalent of autorelease?
Generally after the last strong variable is nilled, the object is released immediately. If you store it in a property, you can nil the property, assign it to something like __strong Foo *temp = self.bar; before you nil, and return that local __strong variable (although arc normally detects the return, and inferes the __strong byitself).
Some more details on that: Handling Pointer-to-Pointer Ownership Issues in ARC
DeanWombourne's answer is correct; but to add to (1).
In particular, the compiler may significantly re-order statements as a part of optimization. While method calls will always occur in the order written in code (because any method call may have side effects), any atomic expression may be re-ordered by the compiler as long as that re-order doesn't impact behavior. Same thing goes for local variable re-use, etc...
Thus, the ARC compiler will guarantee that a pointer is valid for as long as it is needed, no more. But there is no guarantee when the pointed to object might be released other than that it isn't going to happen beyond the scope of declaration. There is also no guarantee that object A is released before B simply because A is declared and last used before B.
IN other words, as long as you write your code without relying on side effects and race conditions, it should all just work.
Please keep you code proper as it has diffrent behaviour on diffrent complier.

Resources