提问人:isaiah 提问时间:7/4/2020 更新时间:10/22/2021 访问量:326
不带 return 语句的 Obj-C 方法如果包含 @try @catch 块,则对其进行编译
Obj-C method without return statement compiles if it includes a @try @catch block
问:
问:如何让 Xcode 报告丢失的退货?
下面是一个新的 Xcode 11 测试应用程序。我添加了一个空的 @try/@catch 块且没有返回值的方法。这样可以编译和分析,而不会出现警告或错误。shouldReturnAnObject
#import "AppDelegate.h"
@interface AppDelegate ()
@property (weak) IBOutlet NSWindow *window;
@end
@implementation AppDelegate
- (nonnull id)shouldReturnAnObject {
@try {
} @catch (NSException *exception) {
} @finally {
}
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
id obj = [self shouldReturnAnObject];
NSLog(@"obj: %@", obj);
}
@end
如果我从中删除@try块,则无法编译并显示错误:。这是我期望的任何没有返回返回的方法的行为。Control reaches end of non-void function
版本:Xcode 11.5, macOS 10.15.5.未更改生成设置。
添加不会更改行为。-Wall
我知道 Cocoa 的最佳实践是仅将异常用作例外。真正的应用很少使用异常,只是为了防止真正的异常行为。我提供了一个简单的测试应用程序来专注于这个问题。
我相信这种行为在 Xcode/Clang 中已经存在了很长时间。如果这种行为是故意的,有人可以解释为什么这种行为存在吗?
相关信息: 我还在以下语言中构建了快速测试应用程序:
- C++ (Clang++):编译失败并出现错误
-Wreturn-type
- Java():编译失败,并显示
error: missing return statement
- Objective-C++(使用 .mm 文件):无警告、无错误、编译成功
答:
对我来说,这绝对是一个编译器错误。(您可以在 https://bugs.llvm.org/ 提交错误)证据如下。
我尝试了以下方法,但问题仍然存在:
@try {} @catch (NSException *e) {}
没有@finally
@try {} @finally {}
没有@catch
+
而不是-
- 地址清理器
- 未定义的行为清理器
-Weverything
尽管编译器拒绝生成警告,但您可以看到使用 LLDB 生成了一个实际上完全空的方法体(启用了优化):
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
* frame #0: 0x0000000100000eb4 asdf`-[MyObj shouldReturnAnObject](self=0x0000000103108440, _cmd="shouldReturnAnObject") at main.m:23:1 [opt]
frame #1: 0x0000000100000eee asdf`main(argc=<unavailable>, argv=<unavailable>) at main.m:31:79 [opt]
frame #2: 0x00007fff684f6cc9 libdyld.dylib`start + 1
frame #3: 0x00007fff684f6cc9 libdyld.dylib`start + 1
(lldb) disassemble
asdf`-[MyObj shouldReturnAnObject]:
0x100000eb0 <+0>: pushq %rbp
0x100000eb1 <+1>: movq %rsp, %rbp
-> 0x100000eb4 <+4>: popq %rbp
0x100000eb5 <+5>: retq
0x100000eb6 <+6>: nopw %cs:(%rax,%rax)
https://godbolt.org/z/ZkF48u 显示了相同的内容,尽管程序无法链接,因为那里没有可用的 Obj-C 运行时。你可以尝试不同的编译器版本——事实上,这个问题似乎至少从 Clang 3.0.0 开始就已经存在了。
最后,通过一些运气/小心,您可以观察到缺少返回值会导致未定义的行为。在这里,程序只是抓取堆栈上已经存在的任何内容,例如字符串,而不是缺少的返回值:
评论
try
eax
后续说明:
在 clang 中找到案件的功劳归@jtbandes。 看起来这个案子只是没有实施。https://github.com/llvm/llvm-project/blob/master/clang/lib/Analysis/CFG.cpp#L3666
他还追踪了 11 年前的原始“FIXME”提交。https://twitter.com/jtbandes/status/1279870326784929792
我已经向 Apple 提交了 ~radar~ Feedback Assistant bug:FB7851551
我没有 llvm 贡献者帐户,并且由于垃圾邮件,他们没有接受新成员,所以不能在那里提交错误。如果其他人愿意,那就太棒了。如果他们确实授予我一个帐户,我也会在那里跟进错误报告。
这样一来,我认为这个案子就结了。也许运气好的话,它可以在今年秋天进入 SDK 的最终版本。😃 感谢大家帮助我找到这个。
这是一个错误。此字段存在一个 LLVM 错误,https://llvm.org/PR46693
评论
try ... catch
if
if
if (false)