0

我有一个 iOS 应用程序,它做了很多低级套接字工作,最近在添加 IPv6 支持后,我注意到在运行我的应用程序时有时会发生内核恐慌。整个设备重新启动,我得到一个包含很多神秘信息的恐慌文件(包括我的应用程序中没有堆栈帧),但有一些关键信息如下所示:

panic(cpu 0 caller 0xffffff800f15fba0): assertion failed: se->se_flags & SEF_ATTACHED, file: /SourceCache/xnu/xnu-2784.30.7/bsd/kern/uipc_socket.c, line:     6228
Debugger message: panic

幸运的是这个模块是开源的,我在这里找到了关闭版本的代码:http: //opensource.apple.com//source/xnu/xnu-2782.1.97/bsd/kern/uipc_socket.c

该错误似乎与此功能相匹配:

void
sockaddrlist_remove(struct sockaddr_list *sl, struct sockaddr_entry *se)
{
    VERIFY(se->se_flags & SEF_ATTACHED);
    se->se_flags &= ~SEF_ATTACHED;
    VERIFY(sl->sl_cnt != 0);
    sl->sl_cnt--;
    TAILQ_REMOVE(&sl->sl_head, se, se_link);
}

我很确定第一个 VERIFY() 基本上是一个断言,它失败了。

但是,这只是告诉我,在这段代码运行之前的某个时间,我的程序可能损坏了一些内存。因此,像大多数内存损坏一样,找到原因非常具有挑战性。

根据我的日志记录,我看到这种情况发生在大致一些网络调用之后,包括 socket()、connect()、read() 和 write(),尽管在这里给出代码是不可行的。

另一条信息是这只发生在 IPv6 上。在 IPv4 上,一切正常。但是我已经清理了 IPv6 代码,并没有发现任何明显错误的地方。我也很困惑用户空间中的任何内存损坏问题都会导致内核失败。也许了解这会如​​何发生将有助于我追踪问题。

大多数人会说的下一步是尝试保护 malloc,但不幸的是,当我尝试打开它时,我遇到了另一个问题,所以现在让我们假设我目前不能使用保护 malloc。

我还尝试在运行时实时附加到程序并使其崩溃,但它不会在任何地方的调试器中停止,它只是重新启动整个设备(iPad)。

如果有人对这个棘手的错误有任何分类的想法,请告诉我。

编辑:

根据其中一个答案的反馈,我检查了相关套接字 API 调用的所有长度,这些似乎是正确的。所以这里似乎还有其他问题,可能会覆盖内存。

我可以尝试使用“Malloc Guard Edges”,但问题停止发生。我不能使用“Guard Malloc”,因为它只能在模拟器上运行,而且由于它与硬件的交互方式,我的应用程序在模拟器上运行不佳。

如果有人有更多想法,请告诉我。

4

1 回答 1

2

我已经看到这种情况发生(iOS 应用程序中的 IPv6 更改编码不正确导致整个手机重新启动)。

sendto()在我的情况下,这是由于使用错误的系统调用引起的,它与dest_len指向的结构的大小不匹配dest_addr。添加对 IPv6 的支持时可能会出现这种问题,因为当一切都是 IPv4 时,所有sockaddr结构都是sockaddr_in,具有相同的大小,可以硬编码,但是当你可以拥有 IPv4 和 IPv6 地址时,你可以有不同的大小的结构,并且您必须传递与传递的结构相对应的正确长度。您的特定问题可能不完全存在sendto(),但它可能是一个类似的问题,因此我会检查您需要传递的每个系统调用 a socklen_t,包括bind()and connect()

我同意应用程序中的任何代码都不应该导致手机重新启动,而且这是可能的事实是 Apple 的错误。

尽管调试器不可能在内核崩溃时停止(因为设备断开连接,因此调试器停止),但您仍然可以通过某种方式对其进行调试,如果您知道它发生的大致位置,您可以逐行调试 -调试器中的行,并查看内核在哪一行发生恐慌。它发生恐慌的那一行将是一个函数调用(恐慌发生在调用内部),因此您现在可以进入该函数调用并重复,直到您将其缩小到特定的系统调用。

于 2016-06-08T02:19:04.357 回答