You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

__asan::ReportGenericError报告位置及macOS守护进程崩溃排查

macOS Launch Daemon退出崩溃排查与ASAN报告位置说明

一、崩溃核心信息

崩溃发生在MyService退出阶段,崩溃栈指向P1Timer::_cancelEvents函数第696行(调用MyFormat格式化字符串的位置),关键崩溃栈片段如下:

Thread 0 Crashed::  Dispatch queue: com.apple.main-thread
0   libsystem_kernel.dylib                 0x18fb0c724 __pthread_kill + 8
...
7   libclang_rt.asan_osx_dynamic.dylib         0x104926498 __asan::ReportGenericError(...) + 1436
8   libclang_rt.asan_osx_dynamic.dylib         0x1048fd558 printf_common(...) + 1400
9   libclang_rt.asan_osx_dynamic.dylib         0x1048fd980 wrap_vsnprintf + 176
10  libclang_rt.asan_osx_dynamic.dylib         0x1048fe1b8 wrap_snprintf + 84
11  MyService                              0x104222ce4 P1Timer::_cancelEvents(...) + 780 (P1Timer.h:696)
...
18  MyService                              0x104161908 MySvc::~MySvc() + 228 (MySvc.cpp:160)

触发崩溃的代码片段:

// P1Timer.h:696
std::string strDbgDesc;
MyFormat(strDbgDesc,                         
         "budleID=\"%s\", EventType=\"%s\""
         ,
         pstrBundleID ? pstrBundleID : "<null>",
         pstrEventType ? pstrEventType : "<null>");

调用_cancelEvents的代码:

_cancelEvents(_strTmrBundleID.c_str(), NULL, szCnt);

MyFormat函数实现:

std::string& MyFormat(std::string& str, const char *pFmt, ...)
{
    va_list args;
    va_start (args, pFmt);

    int nchLen = vsnprintf(nullptr, 0, pFmt, args);
    str.resize(nchLen);

    vsnprintf(&str[0], nchLen + 1, pFmt, args);

    va_end(args);
    
    return str;
}

二、崩溃原因分析

  1. va_list重复使用的致命问题
    MyFormat函数中,第一次调用vsnprintf(nullptr, 0, pFmt, args)计算字符串长度时,已经遍历完va_list中的所有参数,导致args指针移动到参数列表末尾。第二次直接复用同一个va_list调用vsnprintf时,会读取超出参数列表范围的内存,触发ASAN的内存非法访问检测,最终调用abort()导致崩溃。

  2. 潜在的对象生命周期风险
    崩溃发生在MySvc的析构函数中,此时_strTmrBundleID作为MySvc的成员变量,可能已处于部分析构状态(若_cancelEvents在成员变量析构后调用),导致c_str()返回的指针指向已释放的内存区域,加剧内存非法访问风险。

三、__asan::ReportGenericError报告的位置

在macOS系统中,ASAN的错误输出默认发送到进程的标准错误流(stderr)。对于Launch Daemon这类后台服务:

  • 终端查看:执行log show --predicate 'process == "MyService"' --info --debug --last 1h(可调整时间范围),过滤MyService相关日志,ASAN的详细错误信息会包含具体内存违规类型(如越界访问、使用已释放内存等)和位置。
  • 图形化查看:打开「控制台.app」,搜索进程名MyService,查找包含ASAN标记的日志条目,获取完整错误详情。

修复建议

  1. 修复MyFormat的va_list使用问题
    通过va_copy复制一份va_list用于第二次调用,避免指针失效:
std::string& MyFormat(std::string& str, const char *pFmt, ...)
{
    va_list args;
    va_start(args, pFmt);
    
    va_list args_copy;
    va_copy(args_copy, args);
    
    int nchLen = vsnprintf(nullptr, 0, pFmt, args);
    str.resize(nchLen);

    vsnprintf(&str[0], nchLen + 1, pFmt, args_copy);

    va_end(args_copy);
    va_end(args);
    
    return str;
}
  1. 确保析构时对象的有效性
    检查MySvc析构函数的执行顺序,保证调用_cancelEvents时,_strTmrBundleID仍处于有效状态(未被析构)。

内容的提问来源于stack exchange,提问作者c00000fd

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 05:37:28