gpt4 book ai didi

objective-c - 为什么 Clang 在没有 return 语句的 block 中被 @try{} 混淆了?

转载 作者:太空狗 更新时间:2023-10-30 03:33:21 26 4
gpt4 key购买 nike

在正常情况下,当一个 block 被声明为返回一个值,但没有 return 语句实际出现在 block 中时,Clang 将无法编译它并出现错误(缺少返回值)。

但是,当该 block 包含 @try{} @catch(...){}@try{} @finally{} 时,这会中断。

有人知道为什么吗?

我发现这一点的方法是在 ReactiveCocoa 的 RACExtScope 中使用 @weakify()@strongify() 时,在一个 block 中我忘记返回信号。但是编译器没有警告我并在运行时崩溃,这导致我深入研究它,预处理代码并发现这是导致它的原因。任何解释将不胜感激,老实说我不知道​​为什么会这样,谢谢!

我还创建了一个要点,以防有人有评论/建议:https://gist.github.com/czechboy0/11358741

int main(int argc, const char * argv[])
{
id (^iReturnStuff)() = ^id() {
@try{} @finally{}
//if you comment out line 4, Clang will not compile this.
//if you leave it like this, Clang will compile and run this, even though
//there's no value being returned.
//is there something special in @try{} that turns off compiler errors?
};
return 0;
}

最佳答案

Clang's block specification简要提及 block 中的控制流。我在这里复制了它(强调我的)

The compound statement of a Block is treated much like a function body with respect to control flow in that goto, break, and continue do not escape the Block. Exceptions are treated normally in that when thrown they pop stack frames until a catch clause is found.

进一步阅读,您会真正感觉到 Objective-C 中的异常是彻头彻尾的怪异。来自 the section on exceptions

The standard Cocoa convention is that exceptions signal programmer error and are not intended to be recovered from. Making code exceptions-safe by default would impose severe runtime and code size penalties on code that typically does not actually care about exceptions safety. Therefore, ARC-generated code leaks by default on exceptions, which is just fine if the process is going to be immediately terminated anyway. Programs which do care about recovering from exceptions should enable the option.

从上面可以合理地推断出 ObjC 异常规范是如此脆弱或可塑,以至于编译器编写者都不能保证针对它的稳定代码,因此一旦 @try-@catch 被禁用,他们就禁用所有合理的终止检查遭遇。

这也可以在 Clang 生成的带有和不带有 try-catch 的代码中看到。一、无

___main_block_invoke:
pushq %rbp
movq %rsp, %rbp
movabsq $0, %rax
movq %rdi, -8(%rbp)
movq %rdi, -16(%rbp)
popq %rbp
ret

这是非常简单的 x86,它压入一个新的堆栈帧,将 0 (nil) 移动到返回寄存器,然后返回。现在,使用 try-catch block :

___main_block_invoke:
pushq %rbp
movq %rsp, %rbp
subq $64, %rsp
movq %rdi, -16(%rbp)
movq %rdi, -24(%rbp)
movb $0, -25(%rbp)
movl -32(%rbp), %eax
testb $1, -25(%rbp)
movl %eax, -48(%rbp) ## 4-byte Spill
jne LBB1_1
jmp LBB1_3
LBB1_1:
callq _objc_exception_rethrow
jmp LBB1_2
LBB1_2:
LBB1_3:
movl -48(%rbp), %eax ## 4-byte Reload
movl %eax, -32(%rbp)
movq -8(%rbp), %rdi
addq $64, %rsp
popq %rbp
jmp _objc_autoreleaseReturnValue ## TAILCALL
LBB1_4:
movl %edx, %ecx
movq %rax, -40(%rbp)
movl %ecx, -44(%rbp)
testb $1, -25(%rbp)
jne LBB1_5
jmp LBB1_7
LBB1_5:
callq _objc_end_catch
jmp LBB1_6
LBB1_6:
jmp LBB1_7
LBB1_7:
jmp LBB1_8
LBB1_8:
movq -40(%rbp), %rdi
callq __Unwind_Resume
LBB1_9:
movq %rdx, -56(%rbp) ## 8-byte Spill
movq %rax, -64(%rbp) ## 8-byte Spill
callq _objc_terminate

除了更复杂的函数 proem,请注意缺少适当的 ret。该函数仍然有两个退出点,

jmp   _objc_autoreleaseReturnValue

call  _objc_terminate

第一个是该语言的一个相对较新的特性,当处于尾调用位置时,它可以用于省略 -autoreleases 以通过检查代码来利用线程局部变量来到它之前。第二个开始立即终止进程并跳转到 C++ 异常处理机制。这意味着该函数实际上确实具有必要的退出点,以防止 CLANG 提示缺少返回语句。不幸的是,这也意味着 CLANG 放弃扰乱 ObjC 异常机制可能会产生垃圾消息,如您所见。这是 EXTScope 拥有 switched to using the @autoreleasepool directive 的原因之一吃那个印记。

关于objective-c - 为什么 Clang 在没有 return 语句的 block 中被 @try{} 混淆了?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23330884/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com