C 带 block : Stack-based blocks going out of scope

标签 c objective-c-blocks grand-central-dispatch

在 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/

相关文章:

检查至少 2 个数字是完全平方数 - C 程序

C++ 保留字作为 C 结构中的函数指针名称

c - 如何在 OpenMP LLVM 中使用运行时跟踪?

ios - 等待 didFinishLaunchingWithOptions 中的服务操作和延迟后调用的 didRegisterForRemoteNotificationsWithDeviceToken

c - C 中 sizeof 运算符中的参数

objective-c - 使用 block 和变量 iOS 的枚举

ios - 属性如何与 "self"相关,反之亦然?

ios - 指定函数 block 是异步与同步的模式

ios - 如何在后台线程中快速将普通数组保存到 Realm 中

ios - 有没有办法限制我的应用程序中GCD产生的线程数?