news 2026/5/22 23:41:55

Android应用程序 c/c++ 崩溃排查流程二——AddressSanitizer工具使用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Android应用程序 c/c++ 崩溃排查流程二——AddressSanitizer工具使用

目录

1.背景

2.ASan工具集成到应用中进行使用

3.使用ASan工具查看日志


1.背景

由于在Android应用中进行c/c++编程会有各种crash或者内存指针异常,如果内存需要查看哪地方进行释放内存是无法通过addr2line或者ndk-stack工具排查出来的,这时就需要使用AddressSanitizer对内存异常的进行深度分析,例如list收尾相连成为环形了,如下:

主要代码逻辑如下:

根本原因:Scudo(Android 11+ 的默认内存分配器)检测到要释放的内存块的头部信息(chunk header)已被破坏 。

直接触发点:在osa_free中释放某个内存块(地址0xd0061100)时,Scudo 验证发现其头部校验和不匹配 。头部可能因内存越界写入(如缓冲区溢出)或使用已释放内存(use-after-free)而损坏 。

重要背景:在崩溃前,您的队列验证代码多次检测到并修复了循环链表("Circular list confirmed! Cycle detected after X steps")。队列结构持续被破坏,暗示存在持续的内存越界写入严重的并发访问问题​ 。

Scudo 本身是一种缓解机制,而 ASan 能更精确地定位内存错误,此处就需要用到ASan工具

2.ASan工具集成到应用中进行使用

1.在AndroidManifest.xml中添加:

android:extractNativeLibs="true"

如下:

2.在gradle中添加

useLegacyPackaging = true

如下是我的配置

如果不行直接把我的配置拷贝进去

packagingOptions { jniLibs { useLegacyPackaging = true // 兼容旧版本Gradle } resources { // 包含所有.so文件 pickFirsts += "**/*.so" // 包含静态库(如果需要) pickFirsts += "**/*.a" } }

3、将wrap.sh 文件添加到src/main/resources/lib目录中的对应目录。我这边是32位的,如下:

wrap.sh内容如下,直接拷贝即可:

#!/system/bin/sh HERE="$(cd "$(dirname "$0")" && pwd)" export ASAN_OPTIONS=log_to_syslog=false,allow_user_segv_handler=1 ASAN_LIB=$(ls $HERE/libclang_rt.asan-*-android.so) if [ -f "$HERE/libc++_shared.so" ]; then # Workaround for https://github.com/android-ndk/ndk/issues/988. export LD_PRELOAD="$ASAN_LIB $HERE/libc++_shared.so" else export LD_PRELOAD="$ASAN_LIB" fi "$@"

也可以参考:https://developer.android.com/ndk/guides/asan?hl=zh-cn#ndk-build

4.找到asan的动态库,和其他动态库一样集成到项目中

首先我这边是用的32位库,路径如下:

Sdk\ndk\23.1.7779620\toolchains\llvm\prebuilt\windows-x86_64\lib64\clang\12.0.8\lib\linux

然后集成到项目中,这里的流程就是和一般的so包一样进行集成即可

上述的流程就完成了ASan工具的集成

3.使用ASan工具查看日志

上述集成完成,然后我们运行应用,如果有wrap.sh相关的AddressSanitizer打印说明我们集成成功了,如下:

从ASan报告中有几个关键信息点:

  1. 错误类型AddressSanitizer: attempting free on address which was not malloc()-edSUMMARY: AddressSanitizer: bad-free。这直接指明了是无效的释放操作。

  2. 地址位置Address 0xc99ce0f8 is located in stack of thread T20 (Thread-4)。这是最关键的线索,它表明您的程序试图释放(free)的内存地址是一个位于线程栈(stack)上的局部变量,而栈内存是由系统自动管理(函数返回时自动回收)的,绝不能手动释放。

  3. 调用栈:调用栈显示了从liblpa.so开始的函数调用链,错误就发生在这个库中。您需要沿着这个调用栈来定位问题代码。

然后我们使用addr2line工具进一步定位,不会用addr2line工具的可以看前一篇文章:

https://blog.csdn.net/gongjdde/article/details/155744018?sharetype=blogdetail&sharerId=155744018&sharerefer=PC&sharesource=gongjdde&spm=1011.2480.3001.8118

此时我们就定位到错误的位置了,如下:

可以看出来这个是局部的变量,不能被回收,所以导致出现无效的释放,将这行代码删除即可

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/8 11:28:09

以数字创新激活文化传承:iBox入选2025数字化转型特色案例

近日,中国互联网协会数字化转型与发展工作委员会正式公布了2025年度“互联网助力经济社会数字化转型”案例评审结果。在这一具有行业权威性的评选中,文化数字资产生态平台iBox所申报的《iBox助力文化产业数字化转型创新实践》案例,经多轮严格…

作者头像 李华
网站建设 2026/5/11 20:45:13

高通6490另类使用场景

之前和朋友在闲聊的时候,朋友提出用他是否可以做3D游戏引擎的使用,比如用芯片矩阵,或阵列服务器的方式。仔细想想其实是有机会的。有机会基于高通QCS6490芯片平台(假设您指的是Qualcomm QCS6490 SoC,这是一个常见的边缘计算和IoT处理器)组成芯片矩阵来运行Unity 3D引擎。…

作者头像 李华
网站建设 2026/5/11 9:08:36

C++ 构造函数

一、构造函数的核心定义构造函数是 C 类中一种特殊的成员函数,它的名字和类名完全相同,没有返回值(连 void 都不需要写)。当你创建类的对象时,构造函数会自动被调用,主要用来完成对象的初始化工作&#xff…

作者头像 李华
网站建设 2026/5/12 0:11:06

【光子AI】 FastAPI 极简教程 3

FastAPI 极简教程 文章目录 FastAPI 极简教程 目录 1. FastAPI 简介 1.1 什么是 FastAPI? 1.2 核心技术栈 2. 环境安装与配置 2.1 安装 Python 2.2 创建虚拟环境 2.3 安装 FastAPI 2.4 推荐的开发依赖 3. 第一个 FastAPI 应用 3.1 Hello World 3.2 运行应用 3.3 自动生成的文档…

作者头像 李华
网站建设 2026/5/17 1:22:09

Thinkphp和Laravel框架的简历智能推荐系统_jw8dzu00

目录ThinkPHP与Laravel框架的简历智能推荐系统技术实现要点部署与优化项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理ThinkPHP与Laravel框架的简历智能推荐系统 简历智能推荐系统是一种基于人工智能技术的招聘辅助工具,旨在通过分析求…

作者头像 李华
网站建设 2026/5/13 22:28:38

「从零到一」我用 Node BFF 手撸一个 Vue3 SSR 项目(附源码)

本文介绍如何使用 Node.js 作为中间层(BFF),结合 Vue 3 和 Vite 实现服务端渲染(SSR)。 为什么需要 SSR? 在传统的单页应用(SPA)中,浏览器首先加载一个空白的 HTML&…

作者头像 李华