Why can setting a Block variable inside an if statement cause a carsh? - objective-c

I found an block example in the book "Effective Objective-C 2.0"
void (^block)();
if (/* some condition */) {
block = ^ {
NSLog(#"Block A");
};
} else {
block = ^ {
NSLog(#"Block B");
};
}
block();
The code is dangerous, and here is the explanation in the book:
The two blocks that are defined within the if and else statements are allocated within stack memory. When it allocates stack memory for each block, the compiler is free to overwrite this memory at the end of the scope in which that memory was allocated. So each block is guaranteed to be valid only within its respective if-statement section. The code would compile without error but at runtime may or may not function correctly. If it didn’t decide to produce code that overwrote the chosen block, the code would run without error, but if it did, a crash would certainly occur.
I don't understand the meaning of "If it didn’t decide to produce code that overwrote the chosen block, the code would run without error, but if it did, a crash would certainly occur."
Can someone explain and give examples?

The issue is similar to that of a C array being created locally to a function and then used after the function returns:
#import <Foundation/Foundation.h>
dispatch_block_t global_block;
int * global_arr;
void set_globals(void)
{
if( YES ){
global_block = ^{
NSLog(#"Summer is butter on your chin and corn mush between every tooth.");
};
int arr[5] = {1, 2, 3, 4, 5};
global_arr = arr;
}
}
void write_on_the_stack(int i)
{
int arr[5] = {64, 128, 256, 512, 1024};
int v = arr[3];
dispatch_block_t b = ^{
int j = i + 10;
j += v;
};
b();
}
int main(int argc, const char * argv[])
{
#autoreleasepool {
set_globals();
write_on_the_stack();
global_block();
NSLog(#"%d", global_arr[0]); // Prints garbage
}
return 0;
}
The space on the stack that was used to store the values of the array may be re-used for any purpose. I use the separate function here because it most reliably demonstrates the problem. For your exact case, with the if block and the access in the same function, the compiler is still free to re-use the stack space. It may not, but you can't rely on that. You're breaking the scope rules of the language (derived from C).
As Jesse Rusak and CrimsonChris pointed out in comments, though, with a Block-type variable compiled under ARC, the Block is created on the stack like the array, but copied off the stack (to the heap) when it's stored in a strong pointer. All object pointers, including your global, are strong by default.
If you were not compiling with ARC, this would be unreliable. I can't come up with a failing example with my current compiler, but again, it's breaking the rules and the compiler is under no obligation to do what you want.

Essentially what this is saying is that if there's code running on a separate thread, and something gets assigned to the area of memory currently used by block but before the block() call, then bad things will happen.
void (^block)();
if (/* some condition *)) {
block = ^ {
NSLog(#"Block A");
}
} else {
block = ^ {
NSLog(#"Block B");
}
}
<--- another thread overwrites the **block** block
block(); <--- runtime error since **block** has been dereferenced.

Related

Callback when a block is deallocated

I am calling into Cocoa from C, all through the Obj-C runtime.
I am able to create block objects with the info from here[1] and pass them as arguments to Cocoa methods which retain them as needed, and release them when they are no longer needed. The problem is that I need to release other resources associated with the block when the block reaches refcount 0 and is deallocated, so I need a way to set a callback for when that happens.
With normal objects, I would just subclass and override dealloc(). I hear blocks are objects too - is there a Block class that can be subclassed? Or is there any other way to hook up a function on release and/or dealloc of blocks?
Thanks.
[1] http://clang.llvm.org/docs/Block-ABI-Apple.html
You can use the Obj-C Associated Objects API to associate an object instance with a block instance. The associated object will (if it is not accessed anywhere else) be deallocated when the block is deallocated.
Use the -dealloc method of the associated object to execute any desired resource cleanup, etc.
Expanding on my comment:
I'll assume you are using the Clang compiler to create your blocks in C, if you are creating the block description structs yourself the idea is the same but you can create the structs directly with the correct values.
If you wish to call a cleanup function when a block is disposed of then (in outline):
if (bObject->flags & BLOCK_HAS_COPY_DISPOSE)
{
// block already has a dispose helper
// save current dispose helper in a lookup table with key the bObject
bObject->descriptor->dispose_helper = function which:
a) uses the lookup table to call the original helper
b) removes the entry from the lookup table
c) calls your cleanup function
}
else
{
// block does not have a dispose helper
bObject->flags |= BLOCK_HAS_COPY_DISPOSE; // set is has helpers
bObject->descriptor->copy_helper = dummy copy function
bObject->descriptor->dispose_helper = dispose function which just calls your cleanup
}
You need a lookup table to store a map from block addresses to helper addresses, e.g. NSMapTable.
HTH
Addendum
As requested in comments my quick'n'dirty test code, it just follows the pseudo-code above. Run this and you should see the second and third blocks get disposed, the first is not as its a static literal and doesn't need disposing.
void DummyBlockCopy(void *src, void *dst)
{
}
void BlockDispose(void *src)
{
printf("BlockDispose %p\n", src);
}
typedef void (*HelperFunction)(void *);
NSMapTable *disposeHelpers;
void BlockDisposeCallExisting(void *src)
{
HelperFunction helper = (__bridge void *)[disposeHelpers objectForKey:(__bridge id)(src)];
if (helper)
{
helper(src);
[disposeHelpers removeObjectForKey:(__bridge id)(src)];
}
printf("BlockDisposeCallExisting %p\n", src);
}
void block_trap_dispose(void *aBlock)
{
BlockObject *bObject = aBlock;
if (bObject->flags & BLOCK_HAS_COPY_DISPOSE)
{
[disposeHelpers setObject:(__bridge id)(void *)bObject->descriptor->dispose_helper forKey:(__bridge id)(aBlock)];
bObject->descriptor->dispose_helper = BlockDisposeCallExisting;
}
else
{
bObject->flags |= BLOCK_HAS_COPY_DISPOSE;
bObject->descriptor->copy_helper = DummyBlockCopy;
bObject->descriptor->dispose_helper = BlockDispose;
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
disposeHelpers = [NSMapTable.alloc initWithKeyOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)
valueOptions:(NSPointerFunctionsOpaqueMemory | NSPointerFunctionsOpaquePersonality)
capacity:2];
void (^b1)(void) = ^{ printf("hello world\n"); };
printf("b1: %p\n", b1);
b1();
block_trap_dispose((__bridge void *)(b1));
int x = 10;
void (^b2)(void) = ^{ printf("x is %d\n", x); };
printf("b2: %p\n", b2);
b2();
block_trap_dispose((__bridge void *)(b2));
NSObject *anObject = NSObject.new;
void (^b3)(void) = ^{ printf("anObject: %p\n", anObject); };
printf("b3: %p\n", b3);
b3();
block_trap_dispose((__bridge void *)(b3));
}
Ok, this is how I solved it.
First I created a block_literal (defined to have a block_descriptor attached).
struct block_descriptor {
unsigned long int reserved; // NULL
unsigned long int size; // sizeof(struct block_literal)
copy_helper_t copy_helper; // IFF (1<<25)
dispose_helper_t dispose_helper; // IFF (1<<25)
};
struct block_literal {
struct block_literal *isa;
int flags;
int reserved;
void *invoke;
struct block_descriptor *descriptor;
struct block_descriptor d; // because they come in pairs
};
This is how you should set the fields:
block.isa = _NSConcreteStackBlock //stack block because global blocks are not copied/disposed
block.flags = 1<<25 //has copy & dispose helpers
block.reserved = 0
block.invoke = my_callback_function
block.descriptor = &block.d
block.d.reserved = 0
block.d.size = sizeof(block_literal)
block.d.copy_helper = my_copy_callback
block.d.dispose_helper = my_dispose_callback
I keep a refcount per each created block which starts at 1, and which is incremented in my_copy_callback and decremented in my_dispose_callback. When the refcount reaches 0 the resources associated with the block gets released.
Note: copy/dispose helpers will not be called on synchronous methods like NSString's enumerateLinesUsingBlock because these methods don't retain/release the block while using it because they assume that the block remains available for the duration of the call. OTOH, an async method like dispatch_async() does invoke the helpers. Calling dispatch_async() multiple times on the same block should show the refcount incremented twice and then decremented.

How to enforce parameters of anonymous blocks to be unused in Objective-C?

I've run into a situation while using a library called TransitionKit (helps you write state machines) where I am want to supply entry and exit actions in the form of a callback.
Sadly, the callbacks include two completely useless parameters. A typical block has to look like this:
^void (TKState *state, TKStateMachine *stateMachine) {
// I TOTALLY don't want parameters `state` or `stateMachine` used here
};
(this is an anonymous code block. Read up on blocks here if you're unclear)
As I've noted in the comment, I really don't want those parameters even mentioned in the body there. I've tried simply removing the parameter names like suggested in this question like so:
^void (TKState *, TKStateMachine *) {
// I foobar all I like here
};
but sadly the code won't compile then :(.
How can I enforce this non-usage of parameters in code?
This is what I could come up with. Quite a hack and relies on the GCC poison pragma, which is not standard but a GNU extension - although, given that you are probably compiling this with clang anyway, it should not be a problem.
#define _state state
#define _stateMachine stateMachine
#pragma GCC poison state stateMachine
Then this compiles:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something();
}
But this doesn't:
^(TKState *_state, TKStateMachine *_stateMachine) {
do_something(state, stateMachine);
}
You could just have a function that took one kind of block, and returned another, like this:
#class TKState, TKStateMachine; // here so this will compile
typedef void (^LongStateBlock)(TKState *state, TKStateMachine *stateMachine);
static inline LongStateBlock Adapter(void(^block)()) {
void(^heapBlock)() = [block copy]; // forces block to be on heap rather than stack, a one-time expense
LongStateBlock longBlock = ^(TKState *s __unused, TKStateMachine *sm __unused) {
heapBlock();
};
// this is the non-ARC, MRR version; I'll leave ARC for the interested observer
[heapBlock release];
return [[longBlock copy] autorelease];
}
And in practice:
// this represents a library method
- (void)takesLongStateBlock:(LongStateBlock)longBlock
{
// which hopefully wouldn't look exactly like this
if (longBlock) longBlock(nil, nil);
}
- (void)yourRandomMethod
{
[self takesLongStateBlock:^(TKState *state, TKStateMachine *stateMachine) {
NSLog(#"Gratuitous parameters, AAAAHHHH!");
}];
[self takesLongStateBlock:Adapter(^{
NSLog(#"So, so clean.");
})];
}
The whole thing is gisted, and should compile inside any class. It does what you expect when you call -yourRandomMethod.
AFAIK there is no way to do what you want when you are creating a block, you can only miss the parameter names when you are declaring a block variable(a reference to a block, to avoid misunderstandings)
So here you can miss the param names:
void (^myBlock)(SomeClass *);
But not when you create a block:
myBlock = ^(SomeClass *o)
{
};
I'd write
^void (TKState *unused_state, TKStateMachine *unused_stateMachine) {
// Anyone using unused_state or unused_stateMachine gets what they deserve.
};
Of course someone can use the parameters. But then whatever you do, they can change the code. If someone is intent on shooting themselves in the foot, there is no stopping them.

Don't understand example given of block scope

In the Apple block documentation is an example of code not to write:
void dontDoThisEither() {
void (^block) (void);
int i = random();
if (i > 1000) {
block = ^{printf("got i at: %d\n", i); };
}
// ...
}
The comments for the code say the block literal scope is the "then" clause.
I don't understand what they mean by that, there is no then clause, which is presumably why they have put it in quotes. But why have they put it in quotes and what is the relationship to the block's scope?
Think of an if statement as:
if this then that else this other thing
The {... block = ...} is in the then that part of the if statement. That is, it is *a sub-scope of the scope of the dontDoThisEither() function.
Because blocks are created on the stack and are only valid within the scope of their declaration, that means that the block assignment in that example is only valid within the then that scope of the if statement.
I.e. Consider:
void dontDoThisEither() {
void (^block) (void);
int i = random();
if (i > 1000) {
block = ^{printf("got i at: %d\n", i); };
} else {
block = ^{printf("your number is weak and small. ignored.\n");};
}
block();
}
At the time block(); is executed the block that it is pointing to is in a scope that is no longer valid and the behavior will be undefined (and likely crashy in a real world example).

Is there a way to wrap an ObjectiveC block into function pointer?

I have to provide a C-style callback for a specific C library in an iOS app. The callback has no void *userData or something similar. So I am not able to loop in a context. I'd like to avoid introducing a global context to solve this. An ideal solution would be an Objective-C block.
My question: Is there a way to 'cast' a block into a function pointer or to wrap/cloak it somehow?
Technically, you could get access to a function pointer for the block. But it's totally unsafe to do so, so I certainly don't recommend it. To see how, consider the following example:
#import <Foundation/Foundation.h>
struct Block_layout {
void *isa;
int flags;
int reserved;
void (*invoke)(void *, ...);
struct Block_descriptor *descriptor;
};
int main(int argc, char *argv[]) {
#autoreleasepool {
// Block that doesn't take or return anything
void(^block)() = ^{
NSLog(#"Howdy %i", argc);
};
// Cast to a struct with the same memory layout
struct Block_layout *blockStr = (struct Block_layout *)(__bridge void *)block;
// Now do same as `block()':
blockStr->invoke(blockStr);
// Block that takes an int and returns an int
int(^returnBlock)(int) = ^int(int a){
return a;
};
// Cast to a struct with the same memory layout
struct Block_layout *blockStr2 = (struct Block_layout *)(__bridge void *)returnBlock;
// Now do same as `returnBlock(argc)':
int ret = ((int(*)(void*, int a, ...))(blockStr2->invoke))(blockStr2, argc);
NSLog(#"ret = %i", ret);
}
}
Running that yields:
Howdy 1
ret = 1
Which is what we'd expect from purely executing those blocks directly with block(). So, you could use invoke as your function pointer.
But as I say, this is totally unsafe. Don't actually use this!
If you want to see a write-up of a way to do what you're asking, then check this out:
http://www.mikeash.com/pyblog/friday-qa-2010-02-12-trampolining-blocks-with-mutable-code.html
It's just a great write-up of what you would need to do to get this to work. Sadly, it's never going to work on iOS though (since you need to mark a page as executable which you're not allowed to do within your app's sandbox). But nevertheless, a great article.
If your block needs context information, and the callback does not offer any context, I'm afraid the answer is a clear no. Blocks have to store context information somewhere, so you will never be able to cast such a block into a no-arguments function pointer.
A carefully designed global variable approach is probably the best solution in this case.
MABlockClosure can do exactly this. But it may be overkill for whatever you need.
I know this has been solved but, for interested parties, I have another solution.
Remap the entire function to a new address space. The new resulting address can be used as a key to the required data.
#import <mach/mach_init.h>
#import <mach/vm_map.h>
void *remap_address(void* address, int page_count)
{
vm_address_t source_address = (vm_address_t) address;
vm_address_t source_page = source_address & ~PAGE_MASK;
vm_address_t destination_page = 0;
vm_prot_t cur_prot;
vm_prot_t max_prot;
kern_return_t status = vm_remap(mach_task_self(),
&destination_page,
PAGE_SIZE*(page_count ? page_count : 4),
0,
VM_FLAGS_ANYWHERE,
mach_task_self(),
source_page,
FALSE,
&cur_prot,
&max_prot,
VM_INHERIT_NONE);
if (status != KERN_SUCCESS)
{
return NULL;
}
vm_address_t destination_address = destination_page | (source_address & PAGE_MASK);
return (void*) destination_address;
}
Remember to handle pages that aren't required anymore and note that it takes a lot more memory per invocation than MABlockClosure.
(Tested on iOS)

Objective-C Blocks, Recursion Fails

Sup guys,
I'm trying to do a function that calls itself but by putting everything on one block,
As you can see, the following function is intended to be called an indefinite amount of times (until arcrandom returns a number lower than 50) and you should expect as an output a variable number of "RUNNING" messages, depending on chance.
void (^_test_closure)(void) = ^ {
NSLog(#"RUNNING");
if(arc4random() % 100 > 50) {
_test_closure();
}
};
_test_closure();
However, when running it, I get an EXC_BAD_ACCESS error and the reason I've found is that when the code tries to calls _test_closure inside of the closure it basically points to nowhere.
Does anyone know how to make the above code work?
You have to declare your block itself as a block variable:
__block void (^_test_closure)();
_test_closure = ^{
NSLog(#"Running...");
if ((arc4random() % 100) > 50) {
_test_closure();
}
}
_test_closure();
Recursion and blocks is tricky. Because a block captures all variables passed in, the variable _test_closure is not initialized yet (and clang should give you a warning:
Block pointer variable '_test_closure' is uninitialized when captured by block
).
There are several ways you can get around this, but the most obvious & simplest is to just make the block itself a __block variable (what #H2CO3 said). This allows the block to be weak-linked almost, so that when you call it again, it is properly initialized.
Another option you have is making the block a global or static, like this:
// outside of 'main', thus being a global variable
void (^blockRecurse)(int) = ^(int level) {
if (level < 0)
return;
NSLog(#"Level: %i", level);
blockRecurse(--level);
};
int main()
{
#autoreleasepool {
blockRecurse(10);
}
}
This means it's not being captured by the block, but instead it's referencing the global / static variable, which can be changed by all code equally.
It works with XCode 5 - no warnings, no retain cycles:
typedef void(^blockT)();
blockT block1;
blockT __block block1recursive;
block1recursive = block1 = ^(){
block1recursive();
};
block1();