Android 12/12L应用频发signal 6(SIGABRT)崩溃无法复现求助
崩溃根因分析
这个崩溃是Android 12/12L系统上ART虚拟机的强校验逻辑触发的主动abort,不是随机内存损坏导致的崩溃:
- 回溯栈里的
art::Thread::ProtectStack是Android 12新增的线程栈保护校验逻辑:ART在创建新线程时,会在线程栈的首尾设置不可读写的guard内存页,用来实时检测栈溢出问题,如果调用mprotect给这部分内存设置保护属性失败,ART会直接终止进程,抛出signal 6 (SIGABRT)。 - 本地无法复现是因为触发条件和应用集成的native代码强相关,普通测试场景覆盖不到:90%以上的同类崩溃都是应用集成的第三方native SDK、自研native层代码hook了系统
pthread_create接口,或者自定义了线程栈分配逻辑,没有适配Android 12的新规则:- 最常见的问题来源是旧版本的应用加固壳、APM性能监控SDK、热修复/插件化框架,这类SDK往往会hook线程创建逻辑自行分配栈内存,要么没有预留guard页的空间,要么提前把栈内存的页属性改成了全读写/可执行,导致ART后续设置保护页时直接失败。
- 少部分情况是应用自研native代码修改了线程栈的内存映射属性,或者自定义线程池时手动分配的栈空间不符合ART的内存布局要求。
- 该崩溃仅出现在Android 12/12L的原因是:Android 12之前的版本就算栈保护页设置失败,ART只会输出warning日志,不会主动终止进程;Android 12把这个校验升级成了致命错误,只要校验不通过就直接abort。
修复方案
- 优先排查所有native依赖的版本,重点检查加固、热修复、APM监控、游戏引擎、音视频类SDK,全部升级到官方明确适配Android 12的最新版本。这类问题绝大多数是第三方SDK版本过低导致的,升级对应SDK后崩溃率会直接降到0。
- 如果是自研native代码触发,逐一排查以下逻辑:
- 不要hook ART内部的线程创建流程,不要修改ART创建的线程的栈内存映射属性
- 如果业务需要自定义pthread栈分配,必须在栈的两端预留至少4KB(一个内存页大小)的空间作为guard页,禁止占用这部分内存
- 不要给栈内存页添加可执行权限,Android 12开始对栈内存的执行权限有严格限制,违规操作会直接触发系统校验失败
- 定位具体问题点的技巧:崩溃发生前libart会输出明确的错误日志,会写明
mprotect调用失败的具体原因(比如内存地址不在合法映射区间、页属性冲突、权限不足),可以直接对应到具体的内存操作来源;如果找不到对应日志,可以在debug包中逐个禁用第三方SDK初始化,二分排查触发问题的模块——这个崩溃是线程创建时必然触发的,只要复现一次就能定位到问题模块。
注意:不要尝试通过拦截系统abort信号的方式绕过这个校验,Android 12后续版本还有更多栈内存相关的安全校验,绕过会导致更多隐蔽的栈溢出、内存损坏问题。
内容的提问来源于stack exchange,提问作者Joe Koch
相关产品推荐
相关产品推荐

