升级到macOS Mojave后,在[NSWindow orderFrontRegardless]中崩溃

5

在升级到Mojave后,遇到了奇怪的崩溃。

没有做任何特殊操作,只是创建了一个NSWindow并调用了orderFrontRegardless

以前一直都很正常。

1   libsystem_platform.dylib            0x00007fff6610ab5d _sigtramp + 29
2   ???                                 0x0000000000000000 0x0 + 0
3   CoreFoundation                      0x00007fff39b00bb6 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
4   CoreFoundation                      0x00007fff39b00b30 ___CFXRegistrationPost_block_invoke + 63
5   CoreFoundation                      0x00007fff39b00a9a _CFXRegistrationPost + 404
6   CoreFoundation                      0x00007fff39b08f48 ___CFXNotificationPost_block_invoke + 87
7   CoreFoundation                      0x00007fff39a71994 -[_CFXNotificationRegistrar find:object:observer:enumerator:] + 1642
8   CoreFoundation                      0x00007fff39a70d47 _CFXNotificationPost + 732
9   Foundation                          0x00007fff3bdab217 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
10  AppKit                              0x00007fff3720538b -[NSWindow _setFrameCommon:display:stashSize:] + 3090
11  AppKit                              0x00007fff37204766 -[NSWindow _setFrame:display:allowImplicitAnimation:stashSize:] + 192
12  AppKit                              0x00007fff3720469f -[NSWindow setFrame:display:] + 51
13  AppKit                              0x00007fff3727aca9 -[NSWindow _reallyDoOrderWindowAboveOrBelow:relativeTo:findKey:forCounter:force:isModal:] + 1336
14  AppKit                              0x00007fff372792a0 -[NSWindow _doOrderWindow:relativeTo:findKey:forCounter:force:isModal:] + 283
15  AppKit                              0x00007fff37a0dce9 -[NSWindow orderFrontRegardless] + 40

代码(控制台应用程序):

NSWindow *window =    [[NSWindow alloc] initWithContentRect:windowRect
styleMask:windowStyle
backing:NSBackingStoreBuffered
defer:NO];

// Since Snow Leopard, programs without application bundles and Info.plist
// files don't get a menubar and can't be brought to the front unless the
// presentation option is changed
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

 [NSApp activateIgnoringOtherApps:YES];
 [window makeKeyAndOrderFront:nil];

可能是通知被发送到一个已释放/死亡的对象。你有最小的代码示例吗? - Warren Burton
@WarrenBurton 我已经添加了代码。 - Alex
这个评论相关吗?即这个应用程序是否没有plist和bundle?我无法在常规的“Cocoa App”模板中重现崩溃。 - Warren Burton
@Mattie 我使用sigaction()和backtrace_symbols_fd()。我已经发布了一个答案,这是一个与此堆栈跟踪完全无关的内存错误。你知道获取有效堆栈跟踪的更好方法吗? - Alex
你不能在信号处理程序中安全地使用 backtrace_symbols_fd。请查看 man sigaction 了解更多细节。我会跟进一个更详细的答案。 - Mattie
显示剩余2条评论
3个回答

4

你如何初始化应用程序?在使用AppKit之前,是否已经初始化了NSApplication

类似于以下步骤应该在main.m中需要:

@autoreleasepool {
    NSApplication* application = NSApplication.sharedApplication;

    AppDelegate* delegate = [[AppDelegate alloc] init];
    application.delegate = delegate;

    [application run];
}

另外,您的代理可能已被释放,因为NSApp对其持有弱引用。


谢谢,我尝试了@autorelease池,但仍然有10%的用户遇到崩溃问题。我认为可能是某个深层次的内存错误,将使用Valgrind在Linux上进行调试。 - Alex

1
你提到你在取消引用未初始化的指针。但是,我从你发布的报告中没有足够的信息来确定这是否(也许是幸运的)为空,还是仅仅是垃圾内存。我假设在某个时候,你因为 EXC_BAD_ACCESS(信号相当于 SIGBUSSIGSEGV,具体取决于情况)而崩溃了。
这里关键的信息是你安装了一个信号处理程序。
信号处理程序通常(但不总是)在崩溃线程上使用相同的堆栈运行。内核使用 _sigtramp 函数注入处理程序。在信号传递期间,当前堆栈状态包含了你需要追踪坏内存访问的信息。但是,你的信号处理程序被调用了。所以它运行了,并且在运行时改变了堆栈。
然后,你的信号处理程序以某种方式完成了。可以使用 sigaction 配置信号处理程序,使进程状态恢复到崩溃事件之前的状态。我不确定你的信号处理程序是如何配置的。但是,最终,我会假设该进程被允许退出。
在此时,Apple的ReportCrash已被触发,将捕获所有线程的回溯,包括信号处理程序离开它们的任何状态。这很关键,因为那不一定是崩溃状态。
增加复杂性的是,backtrace_symbols_fd在信号处理程序中使用完全不安全。异步安全性很具挑战性,从信号处理程序运行代码非常难以正确实现。你可以安全地完成的事情非常少。我相当确定,backtrace_symbols_fd会分配内存。所以,如果你的崩溃发生在内存分配器中的某个位置(听起来像是),你肯定会面临死锁的风险。从回溯来看,似乎就是可能发生的情况。请查阅man sigaction了解更多细节。
更糟糕的是,在信号处理程序帧上展开堆栈特别具有挑战性,因为内核运行你的处理程序时会进行魔法操作。那就是为什么那里有???帧的原因。
总之:
如果没有安装信号处理程序,Apple的ReportCrash将为崩溃线程生成正确(并且可能有用)的回溯。
您提供的堆栈跟踪信息并不完整,很难确定具体问题所在。看起来backtrace_symbols_fd没有很好地展开堆栈,可能是由于在信号处理程序中使用它不合适,也可能是因为它对于这种情况没有足够好的堆栈展开机制。但是,如果没有更多信息,我很难确定。不过,我很惊讶顶部框架是_sigtramp。这没有太多意义。这让我觉得信号处理程序本身可能出了问题。在处理程序中第二次崩溃是有可能的。

苹果的回溯(例如ReportCrash、backtrace_symbols_fd或NSThread的callStackReturnAddresses生成的)可以被信任,只要您在安全环境中小心使用它们。


这非常有用。非常感谢您花费时间。由于我进行了!= NULL检查,它并没有帮助,因为它是指向垃圾的未初始化指针。我正在使用编译成C语言的自己的语言开发此应用程序,并已为每个字段添加了自动指针初始化,以防止再次发生这种情况 :) - Alex
我将从现在开始避免在信号处理程序中调用backtrace_symbols_fd - Alex
非常欢迎!项目听起来很酷,我明白你的想法。 - Mattie
非常欢迎!这个项目听起来很酷,我理解你为什么想要它。在信号处理函数中进行堆栈展开是可能的,只是需要更多手动操作——特别是在 macOS 上。 - Mattie

0
原来我在一个完全不相关的地方发现了一个严重的内存错误,而且在回溯中根本没有提到。
我正在解引用一个未初始化的指针。
这已经是第二次发生了。
在调试内存错误时,请不要相信苹果的回溯信息。
即使使用了libgmalloc。

我发布了一个希望有用的答案。我敢打赌,如果你在没有信号处理程序的情况下重现这个崩溃,你会发现从调试器或ReportCrash(苹果的自动崩溃报告机制)得到的回溯信息更加有用。 - Mattie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接