是“EXC_BREAKPOINT (SIGTRAP)”吗?调试断点导致的异常?
我有一个多线程应用程序,它在我的所有测试机器上都非常稳定,并且对于几乎每一位用户来说似乎都是稳定的(基于没有崩溃投诉)。不过,对于一位好心的用户来说,该应用程序经常崩溃,他发送了崩溃报告。所有崩溃报告(约 10 个连续报告)看起来基本相同:
Date/Time: 2010-04-06 11:44:56.106 -0700
OS Version: Mac OS X 10.6.3 (10D573)
Report Version: 6
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000002, 0x0000000000000000
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 com.apple.CoreFoundation 0x90ab98d4 __CFBasicHashRehash + 3348
1 com.apple.CoreFoundation 0x90adf610 CFBasicHashRemoveValue + 1264
2 com.apple.CoreText 0x94e0069c TCFMutableSet::Intersect(__CFSet const*) const + 126
3 com.apple.CoreText 0x94dfe465 TDescriptorSource::CopyMandatoryMatchableRequest(__CFDictionary const*, __CFSet const*) + 115
4 com.apple.CoreText 0x94dfdda6 TDescriptorSource::CopyDescriptorsForRequest(__CFDictionary const*, __CFSet const*, long (*)(void const*, void const*, void*), void*, unsigned long) const + 40
5 com.apple.CoreText 0x94e00377 TDescriptor::CreateMatchingDescriptors(__CFSet const*, unsigned long) const + 135
6 com.apple.AppKit 0x961f5952 __NSFontFactoryWithName + 904
7 com.apple.AppKit 0x961f54f0 +[NSFont fontWithName:size:] + 39
(....更多文本如下)
首先,我花了很长时间调查 [NSFont fontWithName:size:]。我认为用户的字体可能以某种方式搞砸了,因此 [NSFont fontWithName:size:] 请求了一些不存在的东西并因此失败。我使用 [[NSFontManager sharedFontManager] availableFontNamesWithTraits:NSItalicFontMask] 添加了一堆代码来提前检查字体可用性。遗憾的是,这些改变并没有解决问题。
我现在注意到我忘记删除一些调试断点,包括 _NSLockError、[NSException raise] 和 objc_exception_throw。但是,该应用程序肯定是使用“Release”作为活动构建配置来构建的。我假设使用“Release”配置可以防止设置任何断点 - 但话又说回来,我不确定断点到底是如何工作的,或者程序是否需要从 gdb 内运行才能使断点产生任何效果。
我的问题是:我留下的断点设置可能是用户观察到的崩溃的原因吗?如果是这样,为什么断点只会对这个用户造成问题?如果没有,其他人是否对 [NSFont fontWithName:size:] 有类似的问题?
我可能只是尝试删除断点并将其发送回用户,但我不确定我还给该用户留下了多少货币。我想更广泛地了解保留断点设置是否可能会导致问题(当使用“发布”配置构建应用程序时)。
I have a multithreaded app that is very stable on all my test machines and seems to be stable for almost every one of my users (based on no complaints of crashes). The app crashes frequently for one user, though, who was kind enough to send crash reports. All the crash reports (~10 consecutive reports) look essentially identical:
Date/Time: 2010-04-06 11:44:56.106 -0700
OS Version: Mac OS X 10.6.3 (10D573)
Report Version: 6
Exception Type: EXC_BREAKPOINT (SIGTRAP)
Exception Codes: 0x0000000000000002, 0x0000000000000000
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
Thread 0 Crashed: Dispatch queue: com.apple.main-thread
0 com.apple.CoreFoundation 0x90ab98d4 __CFBasicHashRehash + 3348
1 com.apple.CoreFoundation 0x90adf610 CFBasicHashRemoveValue + 1264
2 com.apple.CoreText 0x94e0069c TCFMutableSet::Intersect(__CFSet const*) const + 126
3 com.apple.CoreText 0x94dfe465 TDescriptorSource::CopyMandatoryMatchableRequest(__CFDictionary const*, __CFSet const*) + 115
4 com.apple.CoreText 0x94dfdda6 TDescriptorSource::CopyDescriptorsForRequest(__CFDictionary const*, __CFSet const*, long (*)(void const*, void const*, void*), void*, unsigned long) const + 40
5 com.apple.CoreText 0x94e00377 TDescriptor::CreateMatchingDescriptors(__CFSet const*, unsigned long) const + 135
6 com.apple.AppKit 0x961f5952 __NSFontFactoryWithName + 904
7 com.apple.AppKit 0x961f54f0 +[NSFont fontWithName:size:] + 39
(....more text follows)
First, I spent a long time investigating [NSFont fontWithName:size:]. I figured that maybe the user's fonts were screwed up somehow, so that [NSFont fontWithName:size:] was requesting something non-existent and failing for that reason. I added a bunch of code using [[NSFontManager sharedFontManager] availableFontNamesWithTraits:NSItalicFontMask] to check for font availability in advance. Sadly, these changes didn't fix the problem.
I've now noticed that I forgot to remove some debugging breakpoints, including _NSLockError, [NSException raise], and objc_exception_throw. However, the app was definitely built using "Release" as the active build configuration. I assume that using the "Release" configuration prevents setting of any breakpoints--but then again I am not sure exactly how breakpoints work or whether the program needs to be run from within gdb for breakpoints to have any effect.
My questions are: could my having left the breakpoints set be the cause of the crashes observed by the user? If so, why would the breakpoints cause a problem only for this one user? If not, has anybody else had similar problems with [NSFont fontWithName:size:]?
I will probably just try removing the breakpoints and sending back to the user, but I'm not sure how much currency I have left with that user. And I'd like to understand more generally whether leaving the breakpoints set could possibly cause a problem (when the app is built using "Release" configuration).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
断点不会写入二进制文件。此人很有可能安装了损坏的操作系统。检查控制台日志中的 dyld 消息。
Breakpoints aren't written to the binary. Odds are good that this person has a broken OS installation. Check the console logs for dyld messages.
不。实际上,反过来说:SIGTRAP(跟踪陷阱)将导致调试器中断(中断)您的程序,就像实际断点一样。但这是因为调试器总是在崩溃和 SIGTRAP 时中断(就像其他几个 信号)是一种崩溃类型。
SIGTRAP 通常是由抛出 NSException 引起的,但并非总是如此 - 甚至可以直接 自己筹集一个。
这些不是断点。其中两个是函数,
-[NSException raise]
是一个方法。您的意思是在这些函数和方法上设置断点吗?
不。
这些配置是构建配置。它们影响 Xcode 构建应用程序的方式。
断点不是构建的一部分;您在调试器中设置它们。它们仅存在,仅被命中,并且仅当您在调试器下运行程序时停止您的程序。
由于它们不是构建的一部分,因此不可能仅通过向用户提供应用程序包来将断点传递给用户。
当您的程序到达断点时,调试器会中断(中断)您的程序,然后您可以检查程序的状态并仔细向前查看程序如何出错。
由于调试器会停止程序,因此当您不在调试器下运行程序时,断点不起作用。
确实如此。调试器断点仅在调试器内起作用。
不。
首先,如上所述,即使这些断点确实以某种方式转移到用户的系统中,断点也只在调试器中有效。如果您的程序未在调试器下运行,则调试器无法在断点处停止。用户几乎肯定没有在调试器下运行您的应用程序,特别是因为他们从中获得了崩溃日志。
即使他们确实在设置了所有这些断点的调试器下运行您的应用程序,只有当您的程序到达该点时才会触发断点,因此只有当您或 Cocoa 调用
_NSLockError
时,这些断点之一才会触发、-[NSException raise]
或objc_exception_throw
。达到这一点并不是问题的原因,而是问题的症状。如果您确实因调用其中之一而崩溃,则您的崩溃日志中将至少有其中一个被命名。事实并非如此。
所以,这与你的断点无关(不同的机器,不涉及调试器),并且它不是 Cocoa 异常 - 正如我提到的,Cocoa 异常是 SIGTRAP 的原因之一,但它们不是唯一的原因。你遇到了一个不一样的人。
我们无法判断我们遇到的问题是否相似,因为您切断了崩溃日志。我们对崩溃发生的上下文一无所知。
唯一需要删除的是“二进制图像”部分,因为我们没有您的 dSYM 包,这意味着我们不能使用该部分来表示崩溃日志。
另一方面,你可以。为此,我编写了一个应用程序;将崩溃日志提供给它,它应该自动检测 dSYM 包(您为您分发的每个版本构建保留 dSYM 包,对吗?)并将函数和方法名称恢复到堆栈跟踪中,无论您的函数和方法出现在哪里。
有关更多信息,请参阅 Xcode 调试指南。
No. Other way around, actually: A SIGTRAP (trace trap) will cause the debugger to break (interrupt) your program, the same way an actual breakpoint would. But that's because the debugger always breaks on a crash, and a SIGTRAP (like several other signals) is one type of crash.
SIGTRAPs are generally caused by NSExceptions being thrown, but not always—it's even possible to directly raise one yourself.
Those are not breakpoints. Two of them are functions and
-[NSException raise]
is a method.Did you mean you set breakpoints on those functions and that method?
No.
The configurations are build configurations. They affect how Xcode builds your applications.
Breakpoints are not part of the build; you set them in the debugger. They only exist, only get hit, and only stop your program when you run your program under the debugger.
Since they aren't part of the build, it's not possible to pass your breakpoints to a user simply by giving them the app bundle.
When your program hits the breakpoint, the debugger breaks (interrupts) your program, whereupon you can examine the program's state and step carefully forward to see how the program goes wrong.
Since it's the debugger that stops your program, breakpoints have no effect when you're not running your program under the debugger.
It does. Debugger breakpoints only work within the debugger.
No.
First, as noted, even if these breakpoints did somehow get carried over to the user's system, breakpoints are only effective in the debugger. The debugger can't stop on a breakpoint if your program isn't running under the debugger. The user almost certainly isn't running your app under the debugger, especially since they got a crash log out of it.
Even if they did run your app under the debugger with all of these breakpoints set, a breakpoint is only hit when your program reaches that point, so one of these breakpoints could only fire if you or Cocoa called
_NSLockError
,-[NSException raise]
, orobjc_exception_throw
. Getting to that point wouldn't be the cause of the problem, it'd be a symptom of the problem.And if you did crash as a result of one of those being called, your crash log would have at least one of them named in it. It doesn't.
So, this wasn't related to your breakpoints (different machine, debugger not involved), and it wasn't a Cocoa exception—as I mentioned, Cocoa exceptions are one cause of SIGTRAPs, but they are not the only one. You encountered a different one.
There's no way we can tell whether any problems we've had are similar because you cut off the crash log. We know nothing about what context the crash happened in.
The only thing that's good to cut out is the “Binary images” section, since we don't have your dSYM bundles, which means we can't use that section to symbolicate the crash log.
You, on the other hand, can. I wrote an app for this purpose; feed the crash log to it, and it should detect the dSYM bundle automatically (you are keeping the dSYM bundle for every Release build you distribute, right?) and restore your function and method names into the stack trace wherever your functions and methods appear.
For further information, see the Xcode Debugging Guide.
该用户极有可能安装了损坏的字体。堆栈跟踪绝对支持这一假设,因为它只影响一个用户这一事实。
在这种情况下,除了让用户删除有问题的字体之外,你无能为力,因为发生的崩溃发生在苹果代码的深处。
尝试让用户在字体簿中运行字体验证。为此,请启动字体簿,单击源列表中的所有字体,然后选择所有列出的字体。然后,您可以从文件菜单中选择验证字体。
It is extremely likely that this user has a corrupt font installed. The stack trace definitely supports that hypothesis, as does the fact that it's only affecting one user.
There's not much you can do in that case except get the user to remove the offending font, as the crashes that occur take place deep down in Apple's code.
Try getting the user to run a font validation in Font Book. To do this, launch Font Book, click All Fonts in the source list and then select all the listed fonts. You can then select Validate Fonts from the File menu.
我有同样的错误。由于无法解释的原因,断点导致了 EXC_BREAKPOINT 异常的抛出。解决方案是删除断点,然后代码就可以工作了。
EXC_BREAKPOINT 是调试器使用的一种异常。当您在代码中设置断点时,编译器会在可执行代码中插入此类异常。当执行到达该点时,抛出异常并且调试器捕获它。然后调试器会在“断点”行中显示您的代码。这就是调试器的工作原理。但在这种情况下,调试器无法正确处理异常,并显示为常规异常错误。
我一生中发现过两次这个错误:
I had the same error. For an unexplainable reason the breakpoint was the responsible of the throwing the EXC_BREAKPOINT exception. The solution was to remove the breakpoint, and then code works.
EXC_BREAKPOINT is a type of exception that debuggers use. When you set a breakpoint in your code, the compiler inserts an exception of this type in the executable code. When the execution reaches that point, the exception is thrown and the debugger catches it. Then the debugger shows your code in the "breakpointed" line. This is how debuggers work. But in this case the debugger does not handle the exception correctly and is presented as a regular exception error.
I have found this error two times in my life: