Android Crash 问题分析以及解决

Crash问题(Java与Native)

1.问题介绍

Crash问题,无论是java侧还是native侧,在日常测试中经常会遇到。
Crash问题一般我们可以分为两类,一类是java侧的crash问题也就是抛出exception问题,这一类相对简单。
另一类是native侧的问题,由于是c++或者是c,所以相对较为复杂。
另外,kernel部分的crash暂且不提。

2.分析过程

分析过程主要分两部分,按照不同的问题来做分析。

(1).java侧问题

java侧出现exception抛出但是并没有栈上任何一层都没有一个地方catch住的话,最终将会使程序崩溃。
这种exception一般最终将会在slog中体现,一般如下所示

12-28 23:32:27.143: D/AndroidRuntime(337): Shutting down VM 
12-28 23:32:27.143: W/dalvikvm(337): threadid=1: thread exiting with uncaught exception (group=0x40015560) 
12-28 23:32:27.173: E/AndroidRuntime(337): FATAL EXCEPTION: main 
12-28 23:32:27.173: E/AndroidRuntime(337): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.wtaylorjr2001.practice/com.wtaylorjr2001.practice.PracticeActivity}: java.lang.NullPointerException 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.ActivityThread.access$1500(ActivityThread.java:117) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.os.Handler.dispatchMessage(Handler.java:99) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.os.Looper.loop(Looper.java:123) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.ActivityThread.main(ActivityThread.java:3683) 
12-28 23:32:27.173: E/AndroidRuntime(337): at java.lang.reflect.Method.invokeNative(Native Method) 
12-28 23:32:27.173: E/AndroidRuntime(337): at java.lang.reflect.Method.invoke(Method.java:507) 
12-28 23:32:27.173: E/AndroidRuntime(337): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
12-28 23:32:27.173: E/AndroidRuntime(337): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
12-28 23:32:27.173: E/AndroidRuntime(337): at dalvik.system.NativeStart.main(Native Method) 
12-28 23:32:27.173: E/AndroidRuntime(337): Caused by: java.lang.NullPointerException 
12-28 23:32:27.173: E/AndroidRuntime(337): at com.wtaylorjr2001.practice.PracticeActivity.onCreate(PracticeActivity.java:24) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 
12-28 23:32:27.173: E/AndroidRuntime(337): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611) 
12-28 23:32:27.173: E/AndroidRuntime(337): ... 11 more 

log中会将该exception的调用栈打出,我们可以跟踪该调用栈进行一步步分析。

此外,由于在一般代码中通常会多次迭代打包exception,比如

1071                try {
1072                    implementation = Class.forName(className, true, cl);
1073                    lastClassName = className;
1074                } catch (Exception e) {
1075                    throw new NoSuchAlgorithmException(type + " " + algorithm + " implementation not found: " + e);
1076                }

如果我们需要查看这个e的调用栈,我们可以在catch block中添加e.printStackTrace()
即可打印Exception e的调用栈。

(2).natvie侧crash问题

native侧crash问题较为复杂。我们需要用到以下工具
32bit:
arm-eabi-addr2line
arm-eabi-gdb
64bit:
aarch64-linux-android-addr2line
aarch64-linux-android-gdb

尽管32bit与64bit工具不同,实际上操作方法一致,我们以64bit为例。

我们举个实际例子来解释
Bug 542978 - [TJ][Telephony][SC9850S][full]点击信息中的网址超链接,偶见“浏览器停止运行”
现在出现一native crash问题,log中有如下错误报告:

Build fingerprint: 'SPRD/sp9850s_2h10_native/sp9850s_2h10:6.0/MRA58K/W16.12.1N15:userdebug/test-keys'
Revision: '0'
ABI: 'arm64'
pid: 6695, tid: 6758, name: Chrome_InProcGp >>> com.android.browser <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), <font color="#FF0000">fault addr 0x170cbeee0</font>
x0 0000000170cbeec0 x1 0000007f7cebecec x2 0000007f7cebecec x3 0000007f8d601054
x4 0000000000000001 x5 0000000000000000 x6 0000014e0000058d x7 0000000200000000
x8 0000000000000000 x9 0000000000182012 x10 0000000000001eee x11 0000000039ca6b46
x12 0000000000000018 x13 ffffffffa91703af x14 0032c69c8c000000 x15 003b9aca00000000
x16 0000007f939018b0 x17 0000007fa5d27854 x18 0000000000000008 x19 0000000170cbeec0
x20 0000000170cbeec0 x21 0000007f7cebecec x22 0000000000000000 x23 0000007f7cebee90
x24 0000000000000001 x25 0000007f93940000 x26 0000007f92851328 x27 0000007f8ce03670
x28 0000000000001000 x29 0000007f7cebeca0 x30 0000007f90ae66f8
sp 0000007f7cebeca0 pc 0000007f90548cd8 pstate 0000000020000000
v0 00000000000000000000000000000000 v1 00000000000000000000000000000000
v2 00000000000000000000000000000000 v3 00000000000000000000000000000000
v4 00000000000031d100000000000021d1 v5 00000000000000040000000000000004
v6 00000000000000020000000000000002 v7 00000000000001d100000000000001d1
v8 00000000000000000000007f8ce03f90 v9 00000000000000000000007fcdb200c8

v10  00000000000000000000007f939681a8  v11  00000000000000000000007f9295f000
v12  00000000000000000000007fa61ec2b8  v13  00000000000000000000007fcdb21c28
v14  00000000000000000000000000000004  v15  00000000000000000000000000000000
v16  00000000000031d100000000000021d1  v17  00000000000000000000000000000000
v18  00000000000031d100000000000021d1  v19  00000000000000004024000000000000
v20  00000000000000004014000000000000  v21  00000000000000004014000000000000
v22  00000000000000000000000000000000  v23  00000000000000003d16800000000000
v24  00000000000000003fe0000000000000  v25  00000000000000003fe00000000000b4
v26  00000000000000003fdffffffffffe98  v27  0000000000000000401c000000000000
v28  00000000000000004022000000000000  v29  00000000000000003fc555555555553e
v30  00000000000000003fc553ad8b79a5cc  v31  00000000000000003fc0e0b02a48f03b
fpsr 00000010  fpcr 00000000

backtrace:
#00 pc 0000000000708cd8 /system/app/webview/webview.apk (offset 0x7fd000)
#01 pc 0000000000ca66f4 /system/app/webview/webview.apk (offset 0x7fd000)
#02 pc 0000000000ca7240 /system/app/webview/webview.apk (offset 0x7fd000)
#03 pc 00000000010fc178 /system/app/webview/webview.apk (offset 0x7fd000)
#04 pc 00000000010ff33c /system/app/webview/webview.apk (offset 0x7fd000)
#05 pc 00000000011103fc /system/app/webview/webview.apk (offset 0x7fd000)
#06 pc 00000000010f934c /system/app/webview/webview.apk (offset 0x7fd000)
#07 pc 00000000010f879c /system/app/webview/webview.apk (offset 0x7fd000)
#08 pc 00000000006e21b0 /system/app/webview/webview.apk (offset 0x7fd000)
#09 pc 00000000006fd00c /system/app/webview/webview.apk (offset 0x7fd000)
#10 pc 00000000006fd91c /system/app/webview/webview.apk (offset 0x7fd000)
#11 pc 00000000006fdeb8 /system/app/webview/webview.apk (offset 0x7fd000)
#12 pc 00000000006fef1c /system/app/webview/webview.apk (offset 0x7fd000)
#13 pc 00000000006fd528 /system/app/webview/webview.apk (offset 0x7fd000)
#14 pc 000000000070de38 /system/app/webview/webview.apk (offset 0x7fd000)
#15 pc 00000000006fc380 /system/app/webview/webview.apk (offset 0x7fd000)
#16 pc 000000000072a0c0 /system/app/webview/webview.apk (offset 0x7fd000)
#17 pc 0000000000726230 /system/app/webview/webview.apk (offset 0x7fd000)
#18 pc 0000000000066ca4 /system/lib64/libc.so (__pthread_start(void*)+52)
#19 pc 000000000001eb84 /system/lib64/libc.so (__start_thread+16)

主要我们首先看该app是以什么abi运行的,这里显示是arm64,所以我们会使用64bit的一套工具。
然后我们看到错误的地址为0x170cbeee0。这里还不是空指针问题,所以我们还需要通过推调用栈分析具体错误位置。

我们找到这个版本对应的带符号表的libwebviewchromium.so(这里说明下,系统级apk如果其中含有so lib,是不会主动将其解压到某一个目录的,故在最终的调用栈中显示的还是webview.apk,但是实际指的即是webview.apk中的libwebviewchromium.so。)

然后执行如下名令:

aarch64-linux-android-addr2line -i -f -e libwebviewchromium.so 0x0000000000708cd8 0x0000000000ca66f4 0x0000000000ca7240 0x00000000010fc178 0x00000000010ff33c 0x00000000011103fc 0x00000000010f934c 0x00000000010f879c 0x00000000006e21b0 0x00000000006fd00c 0x00000000006fd91c 0x00000000006fdeb8

命令后面的各个地址即是各层调用栈的地址,其中以空格分割。

过了一会儿,命令行即会显示:

_ZN4base6Pickle16WriteBytesCommonEPKvm
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/pickle.cc:397
_ZN4base6Pickle16WriteBytesStaticILm4EEEvPKv
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/pickle.cc:380
ZN4base6Pickle8WritePODIiEEbRKT
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/pickle.h:306
_ZN4base6Pickle8WriteIntEi
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/pickle.h:172
_ZN3IPC11ParamTraitsIiE5WriteEPNS_7MessageERKi
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../ipc/ipc_message_utils.h:157
WriteParam<int>
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../ipc/ipc_message_utils.h:103
ZN3IPC11ParamTraitsIN3gpu13CommandBuffer5StateEE5WriteEPNS_7MessageERKS3
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../gpu/ipc/gpu_command_buffer_traits.cc:32
WriteParam<gpu::CommandBuffer::State>
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../ipc/ipc_message_utils.h:103
ZN3IPC11ParamTraitsIN4base5TupleIJRN3gpu13CommandBuffer5StateEEEEE5WriteEPNS_7MessageERKS7
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../ipc/ipc_message_utils.h:607
WriteParam<base::Tuple<gpu::CommandBuffer::State&> >
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../ipc/ipc_message_utils.h:103
ZN3IPC17SyncMessageSchemaIN4base5TupleIJiiEEENS2_IJRN3gpu13CommandBuffer5StateEEEEE16WriteReplyParamsIJS6_EEEvPNS_7MessageEDpT
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../ipc/ipc_message_utils.h:1061
ZN43GpuCommandBufferMsg_WaitForGetOffsetInRange16WriteReplyParamsIN3gpu13CommandBuffer5StateEEEvPN3IPC7MessageET
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../content/common/gpu/gpu_messages.h:531
_ZN7content20GpuCommandBufferStub18CheckCompleteWaitsEv
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../content/common/gpu/gpu_command_buffer_stub.cc:809
_ZN7content20GpuCommandBufferStub17OnMessageReceivedERKN3IPC7MessageE
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../content/common/gpu/gpu_command_buffer_stub.cc:324
_ZN7content13MessageRouter12RouteMessageERKN3IPC7MessageE
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../content/common/message_router.cc:54
_ZN7content10GpuChannel13HandleMessageEv
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../content/common/gpu/gpu_channel.cc:847
ZN4base8internal15RunnableAdapterIMN7content10GpuChannelEFvvEE3RunEPS3
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/bind_internal.h:176 (discriminator 4)
ZN4base8internal12InvokeHelperILb1EvNS0_15RunnableAdapterIMN7content10GpuChannelEFvvEEENS0_8TypeListIJRKNS_7WeakPtrIS4_EEEEEE8MakeItSoES7_SC
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/bind_internal.h:303 (discriminator 4)
_ZN4base8internal7InvokerINS_13IndexSequenceIJLm0EEEENS0_9BindStateINS0_15RunnableAdapterIMN7content10GpuChannelEFvvEEEFvPS7_ENS0_8TypeListIJNS_7WeakPtrIS7_EEEEEEENSD_IJNS0_12UnwrapTraitsISF_EEEEENS0_12InvokeHelperILb1EvSA_NSD_IJRKSF_EEEEEFvvEE3RunEPNS0_13BindStateBaseE
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/bind_internal.h:346 (discriminator 4)
_ZNK4base8CallbackIFvvEE3RunEv
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/callback.h:396 (discriminator 1)
_ZN4base5debug13TaskAnnotator7RunTaskEPKcRKNS_11PendingTaskE
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/debug/task_annotator.cc:51 (discriminator 1)
_ZN4base11MessageLoop7RunTaskERKNS_11PendingTaskE
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/message_loop/message_loop.cc:481
_ZN4base11MessageLoop21DeferOrRunPendingTaskERKNS_11PendingTaskE
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/message_loop/message_loop.cc:490
_ZN4base11MessageLoop6DoWorkEv
/home8/tianqichen/chromium_release_arm64/chromium/src/out/Release/../../base/message_loop/message_loop.cc:602

我们就可以知道大致错误的位置是哪里。
/base/pickle.cc:397

一般来说基本的native crash问题在使用了addr2line工具之后都能够大致分别错误几何。

然而实际上我们去查看该段代码

inline void Pickle::WriteBytesCommon(const void* data, size_t length) {
  DCHECK_NE(kCapacityReadOnly, capacity_after_header_)
      << "oops: pickle is readonly";
  MSAN_CHECK_MEM_IS_INITIALIZED(data, length);
  size_t data_len = bits::Align(length, sizeof(uint32));
  DCHECK_GE(data_len, length);
#ifdef ARCH_CPU_64_BITS
  DCHECK_LE(data_len, kuint32max);
#endif
  DCHECK_LE(write_offset_, kuint32max - data_len);
  size_t new_size = write_offset_ + data_len;  // <----------------------------------- This line.
  if (new_size > capacity_after_header_) {
    size_t new_capacity = capacity_after_header_ * 2;
    const size_t kPickleHeapAlign = 4096;
    if (new_capacity > kPickleHeapAlign)
      new_capacity = bits::Align(new_capacity, kPickleHeapAlign) - kPayloadUnit;
    Resize(std::max(new_capacity, new_size));
  }

  char* write = mutable_payload() + write_offset_;
  memcpy(write, data, length);
  memset(write + length, 0, data_len - length);
  header_->payload_size = static_cast<uint32>(new_size);
  write_offset_ = new_size;
}

size_t new_size = write_offset_ + data_len;
这一段代码看上去并不涉及指针操作,所以一般非代码逻辑问题。因此我们需要进一步通过corefile,查看错误当时具体汇编代码在干什么,当时保存的寄存器以及内存现场是怎么样。

gdb调试corefile

首先如果手机上出现native crash问题,一般都会在手机中生成corefile来dump当时的内存信息。一般会在/data/corefile目录下生成。

分析corefile我们需要用到GDB工具,由于刚才已经从log信息中看到该apk运行在64bit下,故我们将使用aarch64-linux-android-gdb进行分析。

在此之前我们需要准备以下内容。

  • 相应版本的symbols压缩包,并且解压
  • slog中找到corefile

在将symbols解压后(假设我们解压到了当前目录),使用aarch64-linux-android-gdb ./symbols/system/bin/app_process64 命令进入GDB。

进入之后我们可以先设置so的搜索路径,首先由于我们的webview.apk是已经打包好放入源码目录中参加编译的,故该symbols里的lib64目录下并不存在我们的libwebviewchromium.so。再者,由于GDB搜索加载的符号库时是通过名字严格判别,所以我们需要重命名我们的libwebviewchromium.so为webview.apk,然后放入./symbols/system/lib64/中。
之后我们在GDB命令行下执行
set solib-search-path ./symbols/system/lib64/
即指明了so lib的搜索路径。

之后我们可以加载corefile,执行
core-file ./core-file core-Chrome_InProcGp-6695
即可。执行之后需要等一段时间。

待执行完毕后我们即可分析当时crash的现场。

GDB的基本名令有

  • bt 查看当前调用栈
  • f 后续带数字,跳到指定栈以查看寄存器或者汇编代码
  • disassemble 不带内存地址即反汇编当前栈代码,带内存地址即查看该内存地址所在代码段的汇编代码。
  • info registers 查看当前栈的寄存器信息

该问题,我们需要先查看f 0上的汇编代码

(gdb) disassemble
Dump of assembler code for function base::Pickle::WriteBytesStatic<4ul>(void const*):
0x0000007f90548cc0 <+0>: stp x29, x30, [sp,#-48]!
0x0000007f90548cc4 <+4>: mov x29, sp

0x0000007f90548cc8 <+8>: stp x19, x20, [sp,#16]
0x0000007f90548ccc <+12>: str x21, [sp,#32]
0x0000007f90548cd0 <+16>: mov x19, x0
0x0000007f90548cd4 <+20>: mov x21, x1
=> 0x0000007f90548cd8 <+24>: ldr x3, [x0,#32]
0x0000007f90548cdc <+28>: ldr x2, [x0,#24]
0x0000007f90548ce0 <+32>: add x20, x3, #0x4
0x0000007f90548ce4 <+36>: cmp x20, x2
0x0000007f90548ce8 <+40>: b.ls 0x7f90548d0c <base::Pickle::WriteBytesStatic<4ul>(void const)+76>
0x0000007f90548cec <+44>: lsl x1, x2, #1
0x0000007f90548cf0 <+48>: cmp x1, #0x1, lsl #12
0x0000007f90548cf4 <+52>: b.hi 0x7f90548d3c <base::Pickle::WriteBytesStatic<4ul>(void const
)+124>
0x0000007f90548cf8 <+56>: cmp x1, x20
0x0000007f90548cfc <+60>: mov x0, x19

所以错误的位置即为
=> 0x0000007f90548cd8 <+24>: ldr x3, [x0,#32]
即读取x0 + 32这个地址的内容然后放到x 3里去

这时候我们通过info registers 查看x0地址为

(gdb) info registers
x0 0x170cbeec0 6187380416

目测或者严格来说查看map表可以发现这个值作为内存地址来使用应该是不正确的,接下来就是倒推汇编来查看到底这个值是怎么来的。这部分这个问题没有直接证据证明
具体arm汇编指令可以点击这里查看

另外例子有:
Bug 491327 - [BAT][入库预测][SC9830A][5MOD][CMCC][VOLTE][5.1][MTBF][必选项]cer16通过书签打开百度,点击新闻链接,提示很抱歉,“浏览器”已停止运行。

依然我们先从log中找到crash的调用栈

00 pc 007a52b2 /system/lib/libwebviewchromium.so

#01 pc 00ac631b  /system/lib/libwebviewchromium.so
#02 pc 00949239  /system/lib/libwebviewchromium.so
#03 pc 007f2fdf  /system/lib/libwebviewchromium.so
#04 pc 007f603d  /system/lib/libwebviewchromium.so
#05 pc 00809999  /system/lib/libwebviewchromium.so
#06 pc 008099cd  /system/lib/libwebviewchromium.so
#07 pc 007f8043  /system/lib/libwebviewchromium.so
#08 pc 007de197  /system/lib/libwebviewchromium.so
#09 pc 007f8091  /system/lib/libwebviewchromium.so
#10 pc 007de197  /system/lib/libwebviewchromium.so
#11 pc 007f8091  /system/lib/libwebviewchromium.so
#12 pc 007de197  /system/lib/libwebviewchromium.so
#13 pc 007f8091  /system/lib/libwebviewchromium.so
#14 pc 007de197  /system/lib/libwebviewchromium.so
#15 pc 007f8091  /system/lib/libwebviewchromium.so
#16 pc 007de197  /system/lib/libwebviewchromium.so
#17 pc 007f8091  /system/lib/libwebviewchromium.so
#18 pc 007de197  /system/lib/libwebviewchromium.so
#19 pc 007f8091  /system/lib/libwebviewchromium.so
#20 pc 007de197  /system/lib/libwebviewchromium.so
#21 pc 007f8091  /system/lib/libwebviewchromium.so
#22 pc 007fe33b  /system/lib/libwebviewchromium.so
#23 pc 007f610b  /system/lib/libwebviewchromium.so
#24 pc 007f81db  /system/lib/libwebviewchromium.so
#25 pc 007df2e5  /system/lib/libwebviewchromium.so
#26 pc 007f824d  /system/lib/libwebviewchromium.so
#27 pc 007df2e5  /system/lib/libwebviewchromium.so
#28 pc 007f824d  /system/lib/libwebviewchromium.so
#29 pc 007df2e5  /system/lib/libwebviewchromium.so
#30 pc 007f824d  /system/lib/libwebviewchromium.so
#31 pc 007eb4ed  /system/lib/libwebviewchromium.so
#32 pc 007ee833  /system/lib/libwebviewchromium.so
#33 pc 007eea03  /system/lib/libwebviewchromium.so
#34 pc 007ef77f  /system/lib/libwebviewchromium.so
#35 pc 00987ceb  /system/lib/libwebviewchromium.so
#36 pc 00bc058d  /system/lib/libwebviewchromium.so
#37 pc 01288e3b  /system/lib/libwebviewchromium.so
#38 pc 010d9e51  /system/lib/libwebviewchromium.so
#39 pc 00001110  <unknown>

首先我们将其调用栈打印下

bswap32
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/ByteSwap.h:56
bswapuintptrt
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/ByteSwap.h:72
partitionFreelistMask
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/PartitionAlloc.h:329
partitionBucketAlloc
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/PartitionAlloc.h:449
partitionAllocGenericFlags
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/PartitionAlloc.h:546
_ZN3WTF21partitionAllocGenericEPNS_20PartitionRootGenericEj
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/PartitionAlloc.h:554
_ZN3WTF10fastMallocEj
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/FastMalloc.cpp:74
_ZN3WTF10RefCountedIN5blink11RenderStyleEEnwEj
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/wtf/RefCounted.h:166
_ZN5blink11RenderStyle6createEv
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/rendering/style/RenderStyle.cpp:78
_ZN5blink13StyleResolver15styleForElementEPNS_7ElementEPNS_11RenderStyleENS_20StyleSharingBehaviorENS_20RuleMatchingBehaviorE
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/css/resolver/StyleResolver.cpp:582
_ZN5blink7Element24originalStyleForRendererEv
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/dom/Element.cpp:1466
_ZN5blink7Element16styleForRendererEv
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/dom/Element.cpp:1445
_ZNK5blink17RenderTreeBuilder5styleEv
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/dom/RenderTreeBuilder.cpp:99
_ZN5blink17RenderTreeBuilder32createRendererForElementIfNeededEv
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/dom/RenderTreeBuilder.cpp:111
_ZN5blink7Element6attachERKNS_4Node13AttachContextE
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/dom/Element.cpp:1332
_ZN5blink13ContainerNode14attachChildrenERKNS_4Node13AttachContextE
/space/builder/repo/sprdroid5.1_trunk_volte/external/chromium_org/third_party/WebKit/Source/core/dom/ContainerNode.h:291

最后一栈来看
ALWAYS_INLINE uint32_t bswap32(uint32_t x) { return __builtin_bswap32(x); }
看不太出问题所在,总而言之和x有关
这时候需要查看下汇编代码

和之前同样方法进行corefile加载
局部汇编如下:

0xa85bf286 <+146>: movs r0, #1
0xa85bf288 <+148>: add r12, pc
0xa85bf28a <+150>: add.w r2, r12, #112 ; 0x70
0xa85bf28e <+154>: ldrex r1, [r2]
0xa85bf292 <+158>: strex r5, r0, [r2]
0xa85bf296 <+162>: cmp r5, #0
0xa85bf298 <+164>: bne.n 0xa85bf28e <WTF::fastMalloc(unsigned int)+154>
0xa85bf29a <+166>: dmb sy
0xa85bf29e <+170>: cbz r1, 0xa85bf2ac <WTF::fastMalloc(unsigned int)+184>
0xa85bf2a0 <+172>: ldr r1, [pc, #92] ; (0xa85bf300 <WTF::fastMalloc(unsigned int)+268>)
0xa85bf2a2 <+174>: add r1, pc
0xa85bf2a4 <+176>: ldr r0, [r1, #112] ; 0x70
0xa85bf2a6 <+178>: cmp r0, #0
0xa85bf2a8 <+180>: bne.n 0xa85bf2a0 <WTF::fastMalloc(unsigned int)+172>
0xa85bf2aa <+182>: b.n 0xa85bf282 <WTF::fastMalloc(unsigned int)+142>
0xa85bf2ac <+184>: ldr r2, [r3, #0]
0xa85bf2ae <+186>: ldr r1, [r2, #0]
0xa85bf2b0 <+188>: cbz r1, 0xa85bf2c4 <WTF::fastMalloc(unsigned int)+208>
=> 0xa85bf2b2 <+190>: ldr r4, [r1, #0]

此时寄存器信息:

(gdb) info registers 
r0             0x1  1
r1             0x4a6f8ef8   1248825080
r2             0x4b6017a0   1264588704
r3             0xa98fbefc   2844770044
r4             0x38 56
r5             0x0  0
r6             0xa56c5da0   2775342496
r7             0x57209fe4   1461755876
r8             0xa56c6034   2775343156
r9             0xa98dd62c   2844644908
r10            0x4b7180b4   1265729716
r11            0x0  0
r12            0xa98fb7fc   2844768252
sp             0xa56c5ce8   0xa56c5ce8
lr             0xa88e031f   -1467088097
pc             0xa85bf2b2   0xa85bf2b2 <WTF::fastMalloc(unsigned int)+190>
cpsr           0x680d0030   1745682480

所以r1 0x4a6f8ef8这个值没办法读取出来
从corefile对应的map来看,0x4a6f8ef8也确实不在可访问区域中

但是我们看看,其他的内存地址都是0x4b什么什么的,所以可以猜测是否出现读取内存或者写入内存时出现问题

我们假设实际上存着的应该是0x4b6f8ef8
此时我们读取该内存地址的内存来看

(gdb) x /1xw 0x4b6f8ef8
0x4b6f8ef8: 0xc08e6f4b

此时需要结合代码来看,这个x究竟是干嘛用的
结果我们可以发现这边是在做大小端转换工作__builtin_bswap32
也就是说我们内存中读到的值必然是一个经过反转过的内存地址
0xc08e6f4b经过反转为0x4b6f8ec0,按字节倒序,可以访问。

我们再看代码,看下这个传入的x代表什么,我们看到frame 2处

ALWAYS_INLINE PartitionFreelistEntry* partitionFreelistMask(PartitionFreelistEntry* ptr)
{
    // We use bswap on little endian as a fast mask for two reasons:
    // 1) If an object is freed and its vtable used where the attacker doesn't
    // get the chance to run allocations between the free and use, the vtable
    // dereference is likely to fault.
    // 2) If the attacker has a linear buffer overflow and elects to try and
    // corrupt a freelist pointer, partial pointer overwrite attacks are
    // thwarted.
    // For big endian, similar guarantees are arrived at with a negation.
#if CPU(BIG_ENDIAN)
    uintptr_t masked = ~reinterpret_cast<uintptr_t>(ptr);
#else
    uintptr_t masked = bswapuintptrt(reinterpret_cast<uintptr_t>(ptr));
#endif
    return reinterpret_cast<PartitionFreelistEntry*>(masked);
}

可以看到ptr实际是PartitionFreelistEntry*,也就是一个list的入口。
本身PartitionFreelistEntry结构为

struct PartitionFreelistEntry {
    PartitionFreelistEntry* next;
};

那就太简单了,我们只需要看下0x4b6f8ef8是否能够按照next一直下去
由于我们知道是PartitionFreelistEntry*,所以可以使用p /x \*(PartitionFreelistEntry\*)[address]指令来强转查看
于是

(gdb) p /x (PartitionFreelistEntry)0x4b6f8ef8
$1 = {next = 0xc08e6f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f8ec0
$2 = {next = 0x636f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f6300
$3 = {next = 0x58626f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f6258
$4 = {next = 0xa8636f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f63a8
$5 = {next = 0x70636f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f6370
$6 = {next = 0x38636f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f6338
$7 = {next = 0xc8626f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f62c8
$8 = {next = 0xa08f6f4b}
(gdb) p /x (PartitionFreelistEntry)0x4b6f8fa0
$9 = {next = 0xd88f6f4b}
...

证明了9个node应该足够证明推论是正确的

Bug 543783 - [SC9850S][FLAB]Single card (cmcc ),when browsing webpage, Crash "Unfortunately,Browser has stopped"

3.调试技巧

相对来说调试技巧几乎没有,一般都是循序渐进循规蹈矩地按照步骤来查找问题。
Java侧:一般多使用printStackTrace来查看具体exception的throw位置。
C++侧:多使用GDB来熟练技巧。

4.解决思路及解决方案

Java侧:
Java侧一般就两种解决办法:

  1. 把这个throw的exception catch住。
  2. 查看为何抛出这个exception然后解决。

C++侧:

  1. 查看是否存在代码逻辑漏洞导致访问空指针或类似错误,然后修改。
  2. 如果并不存在代码逻辑漏洞,可能存在内存读写问题,需要找到具体位置然后转交系统稳定性同事进行分析。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容