SIGPIPE(Signal 13, Code 0) 异常排查及处理

 更新时间:2023年01月29日 14:00:17   作者:yuec  
这篇文章主要为大家介绍了SIGPIPE(Signal 13, Code 0) 异常排查原因解析及处理详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

问题现象

最近一个版本 APP 更新之后,sentry 大量异常数据上报,影响用户的数量非常夸张 10w +,具体报错如下

排查过程

首先查看 SIGPIPE 的报错原因, 在官网搜索到了相关信息

大意是 Socket 连接关闭后,如果客户端仍在发送数据,这个时候就会产生 SIGPIPE 信号,如果信号没有被处理就会产生崩溃,这里截取了部分关键信息。

文档上说可以使用 signal(SIGPIPE, SIG_IGN) 全局忽略,确认客户端添加了该逻辑,但是异常还是上报到了 sentrysignal 这个函数是给信号关联一个 handler,收到这个信号的时候去执行。 SIG_IGN 是系统提供的忽略信号的处理方式,定义如下:

#define SIG_IGN         (void (*)(int))1

尝试手动触发 SIGPIPE, 运行后可以正常输出。

void signalHandler(int signal) {
    printf("bingo");
}
int main(int argc, char * argv[]) {
    signal(SIGPIPE, signalHandler);
    kill(getpid(), SIGPIPE);
}

多次添加 handler 继续尝试, 控制台输出 333, 也就是说只有最后添加的 handler 会执行到,比较容易理解一个信号只能关联一个 handler

void signalHandler(int signal) {
    printf("111");
}
void signalHandler2(int signal) {
    printf("222");
}
void signalHandler3(int signal) {
    printf("333");
}
int main(int argc, char * argv[]) {
    signal(SIGPIPE, signalHandler);
    signal(SIGPIPE, signalHandler2);
    signal(SIGPIPE, signalHandler3);
    kill(getpid(), SIGPIPE);
}

现状是 sentry 可以捕获并处理这个异常,所以此时怀疑是 sentry 把客户端的处理给覆盖了。

查看 sentry 里面的逻辑,sentry 使用了 sigaction 函数关联 handler,这个函数与 signal 函数一样,可以设置与信号 sig 关联的动作,而 oact 如果不是空指针的话,就用它来保存原先对该信号的动作的位置,act 则用于设置指定信号的动作。sentry 关联了自己的处理 handleSignal 并且会把之前的handler 存储到数组 g_previousSignalHandlers 里面。

int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
// sentry 关联的 action 为 handleSignal
sigaction(fatalSignals[i], &action, &g_previousSignalHandlers[i])

sentryhandleSignal 里面上报异常并且执行了了 sentrycrashcm_handleException,然后使用 raise 重新抛出这个信号。

static void handleSignal(int sigNum, siginfo_t *signalInfo, void *userContext)
{
    SentryCrashLOG_DEBUG("Trapped signal %d", sigNum);
    if (g_isEnabled) {
        // 这里省略上报逻辑
        sentrycrashcm_handleException();
    }
    SentryCrashLOG_DEBUG("Re-raising signal for regular handlers to catch.");
    // This is technically not allowed, but it works in OSX and iOS.
    raise(sigNum);
}

查看 handleException 简化后的调用栈:

void sentrycrashcm_handleException(**struct** SentryCrash_MonitorContext *context)
{
    sentrycrashcm_setActiveMonitors(SentryCrashMonitorTypeNone);
}
void sentrycrashcm_setActiveMonitors(SentryCrashMonitorType monitorTypes)
{
    // isEnabled = false
    setMonitorEnabled(monitor, isEnabled);
}
static inline void setMonitorEnabled(Monitor *monitor, bool isEnabled) {
    uninstallSignalHandler();
}
static void uninstallSignalHandler(void) {
    sigaction(fatalSignals[i], &g_previousSignalHandlers[i], **NULL**);
}

可以看到 handleException 这个函数最终会重新关联保存在 g_previousSignalHandlers里面的 handler,也就是客户端设置的 SIG_IGN 默认忽略。sentry 关联的函数 handleSignal 会在处理完会重新抛出信号,这个信号会触发 SIG_IGN,所以这里并不存在覆盖关系,sentry 不会影响到客户端默认忽略的逻辑。

综上客户端设置的 SIG_IGN 是会生效的,sentry 只是上报了异常,并没有崩溃产生。在 APP 里面手动触发 SIGPIPECharles 抓包可以看到 sentry 上报,APP 未出现崩溃。

原因与处理

和多个业务方确认这个版本并没有 socket 相关的改动,那为什么在这个版本之后突然有大量异常上报呢?

后面 diff 代码发现是改动了 sentry 的初始时机造成的。之前的逻辑是 sentry 初始化,客户端调用 signal 关联 SIG_IGN,这个时候 SIG_IGN 覆盖了 sentrysignalHandler,并且没有保存和恢复之前 handler 的逻辑,sentry 捕获不到信号不会上报,当前版本的改动使这个顺序颠倒了,导致了大量异常数据上报。后续尝试去定位具体的 socket 无果,重新修改了顺序 SIG_IGNsentry 初始化之后关联,之后的版本不再有异常数据上报。

以上就是SIGPIPE(Signal 13, Code 0) 异常排查及处理的详细内容,更多关于SIGPIPE异常排查的资料请关注脚本之家其它相关文章!

相关文章

  • IOS使用TestFlight测试的使用方法

    IOS使用TestFlight测试的使用方法

    TestFlight是iOS系统上用来测试软件的,打开了这个APP就相当于打开了新世界的大门,这个APP直接可以改变你对IOS系统封闭的看法,让你拥有媲美安卓用户的更多自主权!
    2022-12-12
  • iOS整个APP实现灰色主题的示例代码

    iOS整个APP实现灰色主题的示例代码

    这篇文章主要介绍了iOS整个APP实现灰色主题的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • iOS中关于模块化开发解决方案(纯干货)

    iOS中关于模块化开发解决方案(纯干货)

    这篇文章主要介绍了iOS中关于模块化开发解决方案(纯干货)的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • IOS 开发中发送e-mail的几种方法总结

    IOS 开发中发送e-mail的几种方法总结

    这篇文章主要介绍了IOS 开发中发送e-mail的几种方法总结的相关资料,需要的朋友可以参考下
    2017-03-03
  • iOS 判断页面中的该填项是否填完整,改变按钮状态的方法

    iOS 判断页面中的该填项是否填完整,改变按钮状态的方法

    下面小编就为大家分享一篇iOS 判断页面中的该填项是否填完整,改变按钮状态的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-01-01
  • iOS中如何引用另一个工程的方法教程

    iOS中如何引用另一个工程的方法教程

    在iOS开发中,引用另一个工程是大家可能会遇到的一个问题,所以这篇文章主要给大家介绍了关于iOS中如何引用另一个工程的相关资料,文中通过图文介绍的非常详细,对各位iOS开发者们具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-11-11
  • UILabel显示定时器文本跳动问题的解决方法

    UILabel显示定时器文本跳动问题的解决方法

    这篇文章主要给大家介绍了关于UILabel显示定时器文本跳动问题的解决方法,文中通过示例代码介绍的非常详细,对各位iOS开发者们具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-07-07
  • 浅析iOS应用开发中线程间的通信与线程安全问题

    浅析iOS应用开发中线程间的通信与线程安全问题

    这篇文章主要介绍了浅析iOS应用开发中线程间的通信与线程安全问题,谈到了包括互斥锁的使用等设计要点,需要的朋友可以参考下
    2015-11-11
  • iOS实现选项卡效果的方法

    iOS实现选项卡效果的方法

    选项卡在我们日常开发的时候经常要用到,所以这篇文章给大家分享一种iOS实现的简单选项卡效果,很适合大家学习和使用,有需要的可以参考借鉴,下面来一起看看吧。
    2016-09-09
  • iOS 和 Android 哪个更利于赚钱?

    iOS 和 Android 哪个更利于赚钱?

    iOS 和 Android 哪个更利于赚钱?这篇文章为大家揭晓答案,感兴趣的小伙伴们可以参考一下
    2016-09-09

最新评论