TSC扫描与宕机堆栈匹配关联分析应用
一、 核心目标
通过建立TSC扫描结果与client宕机堆栈异常数据之间的关系,快速精准的通过扫描工具定位已导致外网crash的代码问题和原因。同时,衍生评估程序修复TSC扫描问题后,实际外网用户crash问题的改善情况。
二、 问题回顾
Ø 问题现场:三国之刃Clt
Ø crash规模:导致4000 用户crash
Ø 问题原因:
从RDM或BUGLY上报crash堆栈信息,定位导致程序crash的错误代码段。
案例如下:
从crash处的代码分析定位到是getControlLayer()函数空指针导致宕机。
接下来我们发现此问题TSC是能够准确扫描并报错其空指针问题的,如下图:
但为什么程序并没有根据TSC扫描结果提前预防呢?三国之刃此类多级指针的报错多达1.2w ,难以让开发商提前预防保护。
Ø 问题反思:
TSC工具发现的风险点众多时,亦或是crash堆栈的问题列表很长时,这两种无论从哪一方由程序入手排查,如此庞大数量级的工作量都会成为程序入手解决问题的瓶颈。
当然程序可以选择从无数的堆栈中,按照TOP的问题依次排查解决,里面也不乏充满了无法很快定位和解决的问题,此时筛选和第一步剔除冗余信息的快速定位就显得尤为重要了。
Ø 问题解决:
我们尝试将堆栈宕机与TSC扫描已出现的问题进行匹配,精确地定位出已经导致外网crash的风险点,首先解决了快速定位的问题。同时我们也另辟角度如何闭环化跟踪代码修复后的实际效果呢?如何评估用户修复TSC扫描问题后外网crash问题的改善情况呢?我们发现也可以用此堆栈和扫描问题的跟踪来排查效果,累积案例。
三、 自动分析方案设计
1. 前期条件
1) 需要项目每次Rdm/Bugly上传对应版本符号表,由项目测试经理推动。
2) 指定关注的Rdm/Bugly对应版本。
2. 方案流程
![]() |
3. 获取rdm或bugly数据
TSC接入Crash关联方案,只需进行一次项目配置,每天将自动同步外网rdm或者bugly数据。
4. 按照类型过滤Crash问题
针对C /C#不同项目类型,采用不同的过滤标准。
在C 项目我们聚焦空指针和越界类型错误,在RDM上错误类型通常为SIGSEGV和SIGBUS.如图:
在C#项目中,只需关注C#异常类型,而且在C#报错中有更详细的类型划分.如:OverflowException, IndexOutOfRangeException,NullReferenceException等
5. Crash堆栈分析:0级/1级
以TSC空指针扫描为例,大致可以划分为两种:
第一种直接报在空指针解引用处,对应RDM报错Crash中 0级堆栈信息,如图在文件MenuTalks.cs 函数OnMoveNext()中,代码第150行。 m_CurrentDialog2为空时发生空引用,0级堆栈对应RDM堆栈详细如下图:
第二种报错通常为多级调用,对应RDM报错Crash中 1级堆栈信息。如图在文件MD5.cs 函数MD5(const char* szTesxt,int len)中,代码第29行。
szText为空时发生crash,0级堆栈对应的是strlen所在函数,而1级堆栈才是对应的该报错所在的函数MD5()。 对应RDM堆栈详细如下图:
6. TSC扫描问题,堆栈匹配
分析流程:堆栈分析Server—>获取TSC平台Issue—>匹配文件,报错,函数名等信息—>记录堆栈和问题关系—>TSC平台显示结果。
重点问题:编译器由于内部实现的不同而不同,内部实现包括对象在内存中的布局,继承的实现,虚函数调用处理等,所以导致他们的name mangling不是标准化的。很多项目Crash信息使用符号表还原后,表现的堆栈格式也不尽相同。
实际案例:
Ø 如三国之刃IOS在RDM堆栈格式:
级别 | 无效 | 无效 | 类::类::函数(参数)(文件:行号) 换行符; |
0 | sgzr | 0x03a58436 | YiDou::YDTreasureNewPresenter:: onTiXingShow1(YiDou::YDEvent*)(YDTreasureNewPresenter.cpp:640); |
Ø 欢乐斗牛Andriod在RDM堆栈格式:
级别 | 无效 | 无效 | 无效 | 类::类::函数(参数)(文件:行号) 换行符n |
#00 | pc | 0044d4d8 | libNewHLDN.so | cocos2d::extension::CCTweenFunction:: circEaseInOut(float)(/data/rdm/projects /8675/source/client/cocos2d-x-2.2.2/projects/NewHLDN/Game/Project/Android/../../.. /../../extensions/CocoStudio/Armature/utils/CCTweenFunction.cpp:301)
|
Ø 御剑2Andriod在RDM堆栈格式:
级别 | 无效 | 无效 | 无效 | _ZN num类num 函数(文件:行号) xx 换行符n |
#00 | pc | 0010a282 | libyujian.so | _ZN9Animation19getFrameModuleCountEi(/data/rdm/projects/7231/android/jni/../../ yujianonline/Animation/Animation.cpp:585) 0x0 |
这种Name_Manling格式解析详见: https://en.wikipedia.org/wiki/Name_mangling
Ø 天天飞车(Unity项目)Andriod在RDM堆栈格式:
C#报错无堆栈层级,默认自上而下分析,对应0级开始自增。
级别 | 类.函数(参数) |
无 | StringUtility.UTF8BytesToString (System.Byte[]& str)
|
目前我们已经掌握了几种常见的堆栈格式解析,并且会根据新接入项目堆栈特征,自动适配类型,解析出文件名,行号,Crash函数等关键信息。然后,根据TSC扫描报错信息,报错文件,报错类型,报错函数等和堆栈信息匹配记录。结合后推荐适合项目优化修改的代码。
7. TSC推荐结果修复,降低项目Crash率
根据匹配结果,在TSC平台上,我们会根据Crash影响用户数量,分别对CrashTop10,50,100分层推荐,项目组可以根据周期人力,修复Crash关联上的报错。
程序可以在TSC平台打开关联报错,快速跳转到关联RdmCrash堆栈。
四、 项目效果和实际数据举证
在三国之刃项目4.2 版本(平均crash率是3.7%),按照上述方案进行匹配关联分析,并推荐Crash数量在100 空指针问题进行修复。程序修复这些问题后,在三国之刃5.0.0.29版本平均修复率下降到(0.87%)。在TSC和RDM(Bugly)平台验证,这部分问题堆栈确实已无上报。
以下为三国之刃上报次数100 修复问题列表:
序号 | RDM ID | 上报次数 | 报错文件 | 行号 |
1 | 5473 | YDAnimationPlayer.cpp | 257 | |
2 | 4352 | YDHorseSkill.cpp | 96 | |
3 | 886 | YDMiliBookUpgrateMainPresenter.cpp | 149 | |
4 | 493 | YDHorseFeedMainPresenter.cpp | 148 | |
5 | 373 | YDBeautySencePresenter.cpp | 142 | |
6 | 305 | YDTreasureNewPresenter.cpp | 223 | |
7 | 298 | YDCardActivePresenter.cpp | 260 | |
8 | 172 | YDRankMainPresenter.cpp | 207 | |
9 | 164 | YDCmcoat_MStonePresenter.cpp | 162 |
运用同样的方案,我们对全民超神,六龙在天等客户端项目,各自选择一个版本进行分析。排除无法解析的堆栈后,对可识别的错误数据进行匹配,统计用户匹配数量和比例如下:
注:用户匹配比例=匹配用户总数/可识别用户总数(排除堆栈无法解析错误)
以全民超神项目为例,采用此匹配方案,在最优情况下,通过修复TSC推荐关联问题,可识别用户上报数量减少25.28%,可以减少271152个用户异常。
综上,未来我们可以从大量可疑误报中,提炼这部分Crash真实发生的空指针问题共性,从Unity类型错误,类成员空指针错误,函数返回直接解引用,多分支可能返回解引用等分类中,优化扫描粒度,从而更精准的在Crash发生前,提前发现预防。