EXC_GUARD异常 [英] EXC_GUARD exception

查看:160
本文介绍了EXC_GUARD异常的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我尝试关闭套接字句柄时,一个OSX应用程序崩溃了,它在所有以前的平台上都能正常工作,但是在优胜美地中似乎崩溃了.

崩溃的行是

 -(void)stopPacketReceiver{关闭(SD);} 

在Xcode中,它会暂停所有线程并显示EXC_GUARD异常,这是什么类型的异常,有什么想法吗?

谢谢,艾哈迈德(Ahmed)

这是我得到的异常代码

异常类型:EXC_GUARD异常代码:0x4000000100000000、0x08fd4dbfade2dead

解决方案

来自张贴在苹果的旧版本中奎因"The Eskimo"(苹果开发人员关系,开发人员技术支持,核心操作系统/硬件)的开发人员论坛,由我编辑,删除了针对该特定情况的特定内容:

EXC_GUARD是10.9中的一项更改,旨在帮助您检测文件描述符问题.具体来说,系统现在可以标记特定被保护的文件描述符,之后对其进行常规操作这些描述符将触发EXC_GUARD崩溃(当它想要对这些文件描述符进行操作,系统使用特殊的受保护"私有API).

我们将其添加到系统中是因为我们发现很多应用意外关闭文件描述符后神秘崩溃已由系统库打开的文件.例如,如果一个应用关闭用于访问SQLite文件的文件描述符核心数据存储区之后,核心数据将在以后神秘地崩溃上.警卫队例外可以使这些问题尽快得到注意,因此使它们更易于调试.

对于EXC_GUARD崩溃,异常代码如下:

o第一个异常代码…包含三位字段:

  • 高三位……表示[防护类型].

  • 前32位的余数…指示[不允许执行哪个操作].

  • 后32位表示所描述的描述符....

o第二个异常代码是与警卫.…

您的代码正在关闭它不拥有的套接字.也许 sd 包含了您曾经拥有的描述符的描述符编号,但现在是悬挂的引用,因为您已经关闭了描述符,并且该编号现在已被其他人的描述符重用.也许 sd 只是具有某种垃圾值.

我们可以从异常代码中解码出更多信息,但是最有可能的是,您仅需精确跟踪您在整个使用中对 sd 所做的操作即可.


更新:

从已编辑的问题中,我看到您已经发布了异常代码.使用内核源代码中的常量,防护类型为 GUARD_TYPE_FD ,不允许的操作为 kGUARD_EXC_CLOSE (即 close()),描述符为0(FILENO_STDIN).

因此,很可能在未初始化 sd 实例变量时调用了 stopPacketReceiver ,并且默认值为0,该默认值是当对象首次出现时所有实例变量都获得的默认值已分配.

不可思议的值是 0x08fd4dbfade2dead ,根据原始开发人员论坛的帖子,该值表明防护是由SQLite应用的".好像很奇怪描述符0通常从进程启动时打开(也许引用/dev/null).因此,SQLite不应该拥有它.

我怀疑发生的事情是您的代码实际上两次关闭了描述符0.第一次没有受到保护.关闭 FILENO_STDIN 是合法的.程序有时会这样做,以重新打开该描述符以引用其他内容(例如/dev/null),如果它们不需要/需要原始标准输入.在您的情况下,这将是一次事故,但不会引发例外.一旦关闭,描述符将可用于重新分配给打开描述符的下一个对象.我猜那是SQLite.那时,SQLite对描述符进行了防护.然后,您的代码尝试再次将其关闭,并得到 EXC_GUARD 异常.

如果我是对的,那么您的代码得到异常是随机的(尽管它总是做不好的事情).文件描述符0被分配给对其应用了防护的子系统的事实可能是争用情况,也可能是操作系统版本之间操作顺序的改变.

您需要更加小心,不要关闭未打开的描述符.您应该初始化任何用于将文件描述符保存为-1而不是0的实例变量.同样,如果关闭您自己拥有的描述符,则应将实例变量设置回-1.

A OSX app crashes when I try to close a socket handle, it worked fine in all the previous platforms, but it appears to crash in Yosemite.

The line where is crashes is

-(void)stopPacketReceiver
{
   close(sd);
}

In Xcode it pauses all the threads and show EXC_GUARD exception, what kind of exception is this, any ideas ?

Thanks, Ahmed

EDIT:

Here r the exception codes that I get

Exception Type: EXC_GUARD Exception Codes: 0x4000000100000000, 0x08fd4dbfade2dead

解决方案

From a post in Apple's old developer forums from Quinn "The Eskimo" (Apple Developer Relations, Developer Technical Support, Core OS/Hardware), edited by me to remove things which were specific to that specific case:

EXC_GUARD is a change in 10.9 designed to help you detect file descriptor problems. Specifically, the system can now flag specific file descriptors as being guarded, after which normal operations on those descriptors will trigger an EXC_GUARD crash (when it wants to operate on these file descriptors, the system uses special 'guarded' private APIs).

We added this to the system because we found a lot of apps were crashing mysteriously after accidentally closing a file descriptor that had been opened by a system library. For example, if an app closes the file descriptor used to access the SQLite file backing a Core Data store, Core Data would then crash mysteriously much later on. The guard exception gets these problems noticed sooner, and thus makes them easier to debug.

For an EXC_GUARD crash, the exception codes break down as follows:

o The first exception code … contains three bit fields:

  • The top three bits … indicate [the type of guard].

  • The remainder of the top 32 bits … indicate [which operation was disallowed].

  • The bottom 32 bits indicate the descriptor in question ….

o The second exception code is a magic number associated with the guard. …

Your code is closing a socket it doesn't own. Maybe sd contains the descriptor number for a descriptor that you once owned but is now a dangling reference, because you already closed your descriptor and that number has now been reused for somebody else's descriptor. Or maybe sd just has a junk value somehow.

We can decode some more information from the exception codes, but most likely you just have to trace exactly where you're doing with sd over its life.


Update:

From the edited question, I see that you've posted the exception codes. Using the constants from the kernel source, the type of guard is GUARD_TYPE_FD, the operation that was disallowed was kGUARD_EXC_CLOSE (i.e. close()), and the descriptor was 0 (FILENO_STDIN).

So, in all probability, your stopPacketReceiver was called when the sd instance variable was uninitialized and had the default 0 value that all instance variables get when an object is first allocated.

The magic value is 0x08fd4dbfade2dead, which according to the original developer forums post, "indicates that the guard was applied by SQLite". That seems strange. Descriptor 0 would normally be open from process launch (perhaps referencing /dev/null). So, SQLite should not own that.

I suspect what has happened is that your code has actually closed descriptor 0 twice. The first time it was not guarded. It's legal to close FILENO_STDIN. Programs sometimes do it to reopen that descriptor to reference something else (such as /dev/null) if they don't want/need the original standard input. In your case, it would have been an accident but would not have raised an exception. Once it was closed, the descriptor would have been available to be reallocated to the next thing which opened a descriptor. I guess that was SQLite. At that time, SQLite put a guard on the descriptor. Then, your code tried to close it again and got the EXC_GUARD exception.

If I'm right, then it's somewhat random that your code got the exception (although it was always doing something bad). The fact that file descriptor 0 got assigned to a subsystem that applied a guard to it could be a race condition or it could be a change in order of operations between versions of the OS.

You need to be more careful to not close descriptors that you didn't open. You should initialize any instance variable meant to hold a file descriptor to -1, not 0. Likewise, if you close a descriptor that you did own, you should set the instance variable back to -1.

这篇关于EXC_GUARD异常的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆