Sed*_*ien 8 c grand-central-dispatch objective-c-blocks
在Apple的一个头文件中libdispatch,queue.h出现以下警告:
// The declaration of a block allocates storage on the stack.
// Therefore, this is an invalid construct:
dispatch_block_t block;
if (x) {
block = ^{ printf("true\n"); };
} else {
block = ^{ printf("false\n"); };
}
block(); // unsafe!!!
// What is happening behind the scenes:
if (x) {
struct Block __tmp_1 = ...; // setup details
block = &__tmp_1;
} else {
struct Block __tmp_2 = ...; // setup details
block = &__tmp_2;
}
// As the example demonstrates, the address of a stack variable is
// escaping the scope in which it is allocated. That is a classic C bug.
Run Code Online (Sandbox Code Playgroud)
尽我所能,我无法想出一个例证这个bug的测试用例.我可以创建在堆栈上实例化的块,但它们(似乎)总是出现在堆栈上的唯一地址,即使在相互之间超出范围时也是如此.
我想这个答案很简单,但它逃脱了我.任何人都能填补我(有限)理解的空白吗?
编辑:我已经看到了这个回复,但我不太明白该实例如何转换为我上面发布的示例.有人能告诉我一个使用if构造的例子吗?
小智 5
为了使函数内的堆栈闭包崩溃:
你需要确保闭包确实是一个堆栈闭包.从Apple Clang 2.1开始,在当前上下文中不引用变量的闭包(如queue.h中的变量)被实现为全局闭包.这是一个实现细节,可以在不同的编译器/编译器版本之间变化;
编译器必须发出有效重用/重写闭包曾经存在的堆栈区域的代码.否则,该函数内的每个对象都存在于函数堆栈框架中的不同地址中,这意味着您不会在该函数内部发生崩溃.似乎Apple Clang 2.1没有重用堆栈内存地址.GCC 4.6可以重用它们,但它不支持闭包.
由于Apple Clang 2.1没有在函数堆栈框架中重用地址而GCC 4.6不支持闭包,因此我可以告诉它不可能制作这个特定的例子 - 在函数内部,调用超出范围的堆栈关闭 - 崩溃.