在 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.
尽我所能,我无法想出一个示例来说明此错误的测试用例。我可以创建在堆栈上实例化的 block ,但它们(似乎)总是出现在堆栈上的唯一地址,即使彼此超出范围也是如此。
我认为这个问题的答案很简单,但它让我难以理解。任何人都可以填补我(有限)理解中的空白吗?
编辑:我见过this响应,但我不太明白该实例如何转化为我上面发布的示例。有人可以给我看一个使用 if
结构的例子吗?
最佳答案
为了使函数内的堆栈闭包崩溃:
您需要确保闭包确实是堆栈闭包。从 Apple Clang 2.1 开始,不在其当前上下文中引用变量的闭包(如 queue.h 中的闭包)被实现为全局闭包。这是一个实现细节,可能因不同的编译器/编译器版本而异;
编译器必须生成有效重用/重写闭包曾经所在的堆栈区域的代码。否则,该函数内的每个对象都位于函数堆栈帧中的不同地址,这意味着您不会在该函数内发生崩溃。 Apple Clang 2.1 似乎没有重用堆栈内存地址。 GCC 4.6 可以重用它们,但不支持闭包。
由于 Apple Clang 2.1 不在函数堆栈框架中重用地址并且 GCC 4.6 不支持闭包,据我所知,不可能制作这个特定示例 — 在函数内部调用超出范围的堆栈关闭——崩溃。
我在 my blog 上写了一篇关于此的更详细的文字.
关于C 带 block : Stack-based blocks going out of scope,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7439295/