"stack corruption detected"问题探究

问题现象

  • 复现步骤
    • Android 7.0平台
    • 安装手机百度apk(v8.6.5)
    • 启动App后必现native crash

分析定位

初步分析

  • tombstone文件如下

    *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    Native Crash TIME: 959207
    *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
    Revision: '0'
    ABI: 'arm' 
    pid: 3329, tid: 3719, name: bner  >>> com.baidu.searchbox <<<
    signal 6 (SIGABRT), code -6 (SI_TKILL), fault addr --------
    Abort message: 'stack corruption detected'
        r0 00000000  r1 00000e87  r2 00000006  r3 00000008
        r4 84cff978  r5 00000006  r6 84cff920  r7 0000010c
        r8 84cfe708  r9 923fc200  sl 00000000  fp 84cfe694
        ip 0000000d  sp 84cfe530  lr ae08c597  pc ae08edf4  cpsr 000b0010
        d0  0000000000000000  d1  0000000000000000
        d2  0000000000000000  d3  0000000000000000
        d4  0000000000000000  d5  0000000000000000
        d6  0000000000000000  d7  0000000000000000
        d8  0000000000000000  d9  0000000000000000
        d10 0000000000000000  d11 0000000000000000
        d12 0000000000000000  d13 0000000000000000
        d14 0000000000000000  d15 0000000000000000
        d16 005f006b006e0075  d17 003000310033006b
        d18 0000000000052da0  d19 000000000004a938
        d20 000000002000166a  d21 00013093a834e468
        d22 0000000000000000  d23 0000000000000000
        d24 0000004100000052  d25 ffffff79ffffffbb
        d26 0000000000000000  d27 0000000000000000
        d28 0000000000000000  d29 0000000000000000
        d30 0000000000000000  d31 00000000000e8800
        scr 88000093
    
    backtrace:
        #00 pc 00049df4  /system/lib/libc.so (tgkill+12)
        #01 pc 00047593  /system/lib/libc.so (pthread_kill+34)
        #02 pc 0001d855  /system/lib/libc.so (raise+10)
        #03 pc 000193a1  /system/lib/libc.so (__libc_android_abort+34)
        #04 pc 00017014  /system/lib/libc.so (abort+4)
        #05 pc 0001b84f  /system/lib/libc.so (__libc_fatal+22)
        #06 pc 000482ab  /system/lib/libc.so (__stack_chk_fail+6)
        #07 pc 00002c29  /data/app/com.baidu.searchbox-1/lib/arm/libbner.so (getSec+96)
        #08 pc 0000142f  /data/app/com.baidu.searchbox-1/lib/arm/libbner.so (Java_com_bnerclient_InitSo_getSec+2)
        #09 pc 01623e41  /data/app/com.baidu.searchbox-1/oat/arm/base.odex (offset 0x153f000)
    
  • 相关log

    libc打印出"stack corruption detected", 即检测到栈内存被破坏。

    --------- beginning of crash
    06-16 10:02:27.009  3223  3565 F libc    : stack corruption detected
    06-16 10:02:28.126  3223  3565 E jnicrash: finish
    06-16 10:02:28.128  3223  3565 E chromium: [ERROR:zw_microdump_crash_reporter.cc(296)] BREAKPAD ************************************************
    06-16 10:02:28.128  3223  3565 E chromium: [ERROR:zw_microdump_crash_reporter.cc(297)] BREAKPAD Build fingerprint  6, time 2017-06-16 02:02:28.127 UTC 
    06-16 10:02:29.862  3223  3565 W BREAKPAD: Output crash dump file:
    06-16 10:02:29.862  3223  3565 W BREAKPAD: /data/user/0/com.baidu.searchbox/files/zeuslogs//1afdc4cc-7cc6-8598-45991107-0e5e400e.dmp
    06-16 10:02:29.863  3223  3565 W BREAKPAD: /data/user/0/com.baidu.searchbox/files/zeuslogs/8.6.5-25580288-com.baidu.searchbox-8.4.2.345-SP9832A-neon-7.0-0-1497578548127.bdmp
    06-16 10:02:33.370  3223  3565 W google-breakpad: ### ### ### ### ### ### ### ### ### ### ### ### ### 
    

对比实验

  • Nexus 5x/6p(Android 7.0)上无法复现
  • 我司多个产品均能复现
  • 有一台机器(烧录的本地pc编译版本)无法复现

侧面排查

另一同事, 通过对比Jenkins编译版本和我本地编译版本的多个文件,发现/system/build.prop中的ro.build.host属性值存在差异,修改该属性值后问题不再复现。

正面分析

  • 原理

    stack check failed的根本原因在于栈内存被覆盖,编译器会在函数进入和退出前后插入一个stack check的东西用于检测内存越界这种错误。

  • 汇编分析

    • 进入函数时ldr/str

      00002bc8 :
      2bc8:       b5f0            push    {r4, r5, r6, r7, lr}
      2bca:       4d19            ldr     r5, [pc, #100]  ; (2c30 )
      2bcc:       b091            sub     sp, #68 ; 0x44
      2bce:       1c04            adds    r4, r0, #0
      2bd0:       447d            add     r5, pc
      2bd2:       682d            ldr     r5, [r5, #0]
      2bd4:       ae02            add     r6, sp, #8
      2bd6:       9201            str     r2, [sp, #4]
      2bd8:       682b            ldr     r3, [r5, #0]
      2bda:       2100            movs    r1, #0
      2bdc:       2232            movs    r2, #50 ; 0x32
      2bde:       1c30            adds    r0, r6, #0
      2be0:       930f            str     r3, [sp, #60]   ; 0x3c ==> store到[sp + 60]
      
    • 退出函数前检查栈内存是否相同

      ... ...
      2c20:       9a0f            ldr     r2, [sp, #60]   ; 0x3c ==>从[sp + 60] load
      2c22:       682b            ldr     r3, [r5, #0]     
      2c24:       429a            cmp     r2, r3
      2c26:       d001            beq.n   2c2c      相等就正常退出
      2c28:       f000 f94a       bl      2ec0    不相等就跳到__stack_chk_fail执行abort
      2c2c:       b011            add     sp, #68 ; 0x44
      2c2e:       bdf0            pop     {r4, r5, r6, r7, pc}
      

      所以,问题出现后,我们可以查看[sp, #60]附近的内存数据, 就能知道大概什么类型的数据发生内存越界。

    • gdb堆栈和相关寄存器

      (gdb) bt
      #0  tgkill () at bionic/libc/arch-arm/syscalls/tgkill.S:10
      #1  0xae08c596 in pthread_kill (t=, sig=6) at bionic/libc/bionic/pthread_kill.cpp:45
      #2  0xae062858 in raise (sig=3719) at bionic/libc/bionic/raise.cpp:34
      #3  0xae05e3ce in __libc_android_abort () at bionic/libc/bionic/abort.cpp:57
      #4  0xae05c018 in abort () at bionic/libc/arch-arm/bionic/abort_arm.S:43
      #5  0xae060852 in __libc_fatal (format=0x0) at bionic/libc/bionic/libc_logging.cpp:678
      #6  0xae08d2ae in __stack_chk_fail () at bionic/libc/bionic/__stack_chk_fail.cpp:35
      #7  0x9249ec2c in ?? ()
      Backtrace stopped: previous frame identical to this frame (corrupt stack?)
      
      (gdb) f 7
      (gdb) i r
      r0             0x0  0
      r1             0xe87    3719
      r2             0x6  6
      r3             0x8  8
      r4             0x84cfe564   2228217188
      r5             0x84cfe554   2228217172
      r6             0x84cfe5a8   2228217256
      r7             0x84839db0   2223218096
      r8             0x84cfe708   2228217608
      r9             0x923fc200   2453651968
      r10            0x0  0
      r11            0x84cfe694   2228217492
      r12            0xd  13
      sp             0x84cfe550   0x84cfe550
      lr             0xae05e3cf   -1375345713
      pc             0xae05e3ce   0xae05e3ce <__libc_android_abort()+80>
      cpsr           0xb0030  720944
      
    • 查看sp+60附近内存

      (gdb) x /32xw 0x84cfe5a0+60
      0x84cfe5dc: 0x3031336b 0x3230362f 0x8e3a002f 0x84cfe968
      0x84cfe5ec: 0x84cfe708 0x84cfe6c8 0x9249d433 0x74129b00
      0x84cfe5fc: 0x975abe43 0x8e3a7cdc 0x00000000 0x00000002
      0x84cfe60c: 0x12f9d940 0x740fad60 0x00000000 0x923fc28c
      0x84cfe61c: 0x72ce9c55 0x6ff3d9f8 0x00000000 0x00000000
      0x84cfe62c: 0x00000000 0x00000000 0x00000000 0x00000000
      0x84cfe63c: 0x00000000 0x00000000 0x00000000 0x00000000
      0x84cfe64c: 0x00000000 0x00000000 0x00000000 0x00000000
      

      这里很明显是ASCII字符

      (gdb) p (const char *)0x84cfe5dc
      $1 = 0x84cfe5dc "k310/602/"
      

      再往前查看整个字符串,就能看到这是我司特有的一个URL

      (gdb) p (const char *)0x84cfe5a0
      $2 = 0x84cfe5a0 "}\315\377\377\020\346τhttp://10.0.1.97:8080/jenkins/job/sprdroid7.0_trunk_k310/602/"
      
    • 结合汇编code, 猜测这里应是获取某个属性。

      • 现在通过加log, 已确认是App在访问ro.build.host属性导致的。

        06-16 10:08:10.869  1956  2288 E libc    : __system_property_get: property name = "ro.build.host"
        --------- beginning of crash
        06-16 10:08:10.869  1956  2288 F libc    : stack   corruption detected
        
      • 再查看下出问题手机上的ro.build.host的值, 正好对应上

        $adb shell getprop ro.build.host
        http://10.0.1.97:8080/jenkins/job/sprdroid7.0_trunk_k310/602/
        

        长度为62

      • Nexus 6p上该属性的值为

        $ adb shell getprop ro.build.host
        wphr7.hot.corp.google.com
        

        长度为26

      • 本地编译的版本该属性的值为

        $ adb shell getprop ro.build.host
        tj03456pcu1
        

        长度为12
        这基本就确定是获取属性值出现越界。

Root Cause

  • Android定义的属性值最大长度为92。
    #define PROP_VALUE_MAX  92
    
  • 而手机百度App在栈上用于存储property的局部数组size太小,大概为50+左右。所以遇到超过50+字符串,就容易出现栈内存越界了。

解决方案

  • 此问题在我司平台不解决

  • 反馈此问题至百度客服,希望百度解决App栈内存越界问题。

baidu.JPG

你可能感兴趣的:("stack corruption detected"问题探究)