问题
客户反馈了一个 SDK 的 crash log,跑 monkey testing 报出来的问题。trace 信息如下:
精简一下,我们需要关注内容如下:
|
|
和 SDK 相关的只有 #01 pc 000000000007b908 /vendor/lib64/libanc_nightshot.so
这一行。使用 addr2line 定位到地址 7b908 这行代码是使用 memcpy 将 yuv 数据拷贝到客户设置的输出图的 buffer 里面。也和 trace 中紧接着 SDK 的 #00 pc 000000000007f308 /apex/com.android.runtime/lib64/bionic/libc.so (__memcpy+248)
对应了起来。
以前遇到的 crash 问题 trace 里会有多个 SDK 的地址信息,且一般都是 SDK 内部的问题。
但此时只有一行地址信息,而且是挂在 c++ 库函数 memcpy 里。
分析
既然咱们的库没有办法进行分析了,就在想能不能从 libc.so
下手,看一下导致 crash 的 libc.so
的地址 7f308
和 fault addr 0x7740a1d000
处到底发生了什么。
1.根据上面 trace 中的路径将客户手机中的 libc.so
pull 出来,使用 objdump 将 libc.so 的汇编代码反汇编出来:
|
|
2.利用 trace 中的地址 7f308
来在 libc.dump 中定位导致 crash 的汇编代码,地址 7f308
处的汇编代码为:
如何 double check 这一行汇编代码就是真正导致 crash 代码呢?有个办法可以简单验证下,这个是 trace 中关于 memcpy 的那一行:
|
|
根据上面开头的地址,和结尾的偏移量。可以计算出 __memcpy 函数的起始地址是 7f210。(十六进制的 0x7f308 减去 十进制的 248 等于 十六进制的 7f210)
下面是反汇编出来的__memcpy
函数完整的汇编代码(Too long; Don’t read),可以看到 7f210 就是 __memcpy 的起始地址:
|
|
3.搞清楚导致 crash 的汇编代码 7f308: a900340c stp x12, x13, [x0]
的含义
|
|
从这两行 trace 中的 x0 0000007740a1d000
和 fault addr 0x7740a1d000
,可以发现导致 crash 的就是上面这行汇编代码中的 [x0]
下一步就是要搞明白 stp x12, x13, [x0]
在执行什么操作
|
|
在网上查了一下 stp
指令,根据上面的描述大概可以猜出 stp x12, x13, [x0]
是将 x12 和 x13 的值写入到 x0 处,但真正意图还是很模糊。
4.结合 memcpy 的汇编源代码进行分析
在 Android 源码中找到的 memcpy 的汇编语言源程序
下面是反汇编出来的汇编代码和 Android 源码中的汇编源代码的开始部分:
|
|
|
|
对比下上面使用 objdump 出来的汇编代码和 Android 源码中的汇编源代码开始部分,代码是可以对应起来的。两份代码开头这里都是对 memcpy 的第三个参数 count 进行判断,SDK 中调用 memcpy 的地方拷贝长度远大于了 96,所以会走到 copy_long
里去,也就是 7f2f0 <__memcpy+0xe0>
,接着没多久就会走到导致 crash 的 7f308: a900340c stp x12, x13, [x0]
处,对应到汇编源代码中就是 stp D_l, D_h, [dstin]
这一行:
|
|
|
|
所以就是 stp D_l, D_h, [dstin]
这一行导致了 crash,从汇编源代码前面的宏定义可以看到 #define dstin x0
,所以 dstin 就是 x0,而且 x0 就是导致 crash 的 fault addr 0x7740a1d000
,从 trace 中可以看到这两点。
接着从以下三条线索可以得知导致 crash 的 dstin 是 memcpy 要写入的目的地址。
- 结合 Android 源码中 memcpy 的汇编源代码逻辑和 dstin 的命名可以得知 dstin 就是要将 src 写入到的目的地址。
- dstin 和 memcpy 函数定义中的目标地址命名一致:
void *memcpy(void *destin, void *source, unsigned n)
- stp 指令要做的事情就是将值写入到目标地址中。而前几行的 ldp 指令做的事情就是从 src 中将值读出。
5.接下来要做的事情就是确认 SDK 内调用 memcpy 传入的目标地址是什么情况。经检查,目标地址不是 SDK 内部进行分配和管理的,而是由客户传进来的。
结论
所以 crash 的原因是外部分配的地址在 monkey testing 中出现了问题,导致 SDK 在进行 memcpy 将输出拷贝给客户时出现了 crash。
后续
将上面的分析结果发给客户后,客户进行了验证,注释掉在 com.anc.node.nightshot.so 中调用 SDK 接口导致 crash 的代码,直接使用 memcpy,也复现了该问题。证明了该 crash 和 SDK 无关,确实是 memcpy 要写入的目标地址出了问题,最终也解决了此问题。
参考
完整的 Android 源码中的 __memcpy
汇编源代码如下:
|
|