Issues maybe not well backtraced for memcpy

由于memcpy的实现使用了lr寄存器,所以当SIGSEGV发生在memcpy中时,Call Stack未必能很好地追踪出来。

这时可以根据Stack中地址上的符号寻找可能的函数,然后确定发生在memcpy中的是什么问题。

几个示例如下。

(1)

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint:
pid: 325, tid: 4048, name: ExtOutThread >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 41cfe000
r0 4180a190 r1 41cfddc0 r2 00000c00 r3 00000000
r4 4134dee0 r5 40071c18 r6 b3634400 r7 40fbf47c
r8 40fc0d30 r9 40fc0d7c sl 41cfe000 fp 4312deb0
ip 00000020 sp 4312de48 lr 00000280 pc 4019f29c cpsr 20000010
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 20676e696c6c6143 d17 7274705f636e7973
d18 0000000000000000 d19 0000000000000000
d20 0000000000000000 d21 0000000000000000
d22 0000000000000000 d23 0000000000000000
d24 0000000000000000 d25 0000000000000000
d26 0000000000000000 d27 0000000000000000
d28 0000000000000000 d29 0000000000000000
d30 0000000000000000 d31 0000000000000000
scr 80000010

backtrace:
#00 pc 0000e29c /system/lib/libc.so
#01 pc 00026d78 /system/lib/hw/audio.primary.msm8960.so

stack:
4312de08 00000000
4312de0c 00000000
4312de10 00000000
4312de14 00000000
4312de18 00000000
4312de1c 00000000
4312de20 00000000
4312de24 7cea8fed
4312de28 40071c18
4312de2c 00000000
4312de30 00000000
4312de34 40fbf47c /system/lib/hw/audio.primary.msm8960.so
4312de38 00000020
4312de3c 7cea8fed
4312de40 df0027ad
4312de44 00000000
#00 4312de48 4180a010  r0
4312de4c 40fc0d7c /system/lib/hw/audio.primary.msm8960.so r9
#01 4312de50 00000000 r10
4312de54 40fb8e88 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+352) lr
4312de58 00000300
4312de5c 00000300
4312de60 00000157
4312de64 4312deb4 [stack:4048]
4312de68 4134de50 [heap] 
4312de6c 00000000 r4
4312de70 4134ddc8 [heap] r5
4312de74 41915bc8 r6
4312de78 4180ac10 l7
4312de7c 4134de4c [heap] r8
4312de80 00000000 r9
4312de84 40fba94c /system/lib/hw/audio.primary.msm8960.so r10
4312de88 00003e80 r11
4312de8c 40fa8334 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+488) lr

memory near r0:
4180a170 00000000 00000000 00000000 00000000 ................
4180a180 00000000 00000000 00000000 00000000 ................
4180a190 00000000 00000000 00000000 00000000 ................
4180a1a0 00000000 00000000 00000000 00000000 ................
4180a1b0 00000000 00000000 00000000 00000000 ................

memory near r1:
41cfdda0 ffffffff ffffffff ffffffff ffffffff ................
41cfddb0 ffffffff ffffffff ffffffff ffffffff ................
41cfddc0 ffffffff ffffffff ffffffff ffffffff ................
41cfddd0 ffffffff ffffffff ffffffff ffffffff ................
41cfdde0 ffffffff ffffffff ffffffff ffffffff ................

memory near r4:
4134dec0 00000000 00000000 00000000 00000000 ................
4134ded0 00000000 4127b638 419112c8 000000f3 ....8.'A...A....
4134dee0 40fc2ab0 6c616e61 4100676f 4134c327 .*[email protected]'.4A
4134def0

可以看出,backtrace由于使用LR寄存器来反推,memcpy的调用函数并不对,所以得出的backtrace并不准确。

这时可以通过

4312de54 40fb8e88 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+352)

4312de8c 40fa8334 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+488)

来确定调用栈。

(gdb) info symbol 'android_audio_legacy::ALSADevice::readFromProxy'
_ZN20android_audio_legacy10ALSADevice13readFromProxyEPPvPl in section .text
(gdb)disass 'android_audio_legacy::ALSADevice::readFromProxy' or

(gdb)disass _ZN20android_audio_legacy10ALSADevice13readFromProxyEPPvPl

Dump of assembler code for function android_audio_legacy::AudioHardwareALSA::extOutThreadFunc():
   0x0000e14c <+0>: ldr r3, [r0, #116] ; 0x74
   0x0000e150 <+4>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
   0x0000e154 <+8>: cmp r3, #0
  
0x0000e158 <+12>: sub sp, sp, #52 ; 0x34
   0x0000e15c <+16>: mov r5, r0
   0x0000e160 <+20>: beq 0xe564 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+1048>
   0x0000e164 <+24>: ldr r0, [r0, #8]
   0x0000e168 <+28>: bl 0x1f484 <android_audio_legacy::ALSADevice::isProxyDeviceOpened()>
   0x0000e16c <+32>: cmp r0, #0
   ...................................................

   0x0000e2e8 <+412>: bl 0x8e10
   0x0000e2ec <+416>: add sp, sp, #52 ; 0x34
   0x0000e2f0 <+420>: pop {r4, r5, r6, r7, r8, r9, r10, r11, pc}
   0x0000e2f4 <+424>: ldr r0, [r5, #8]
   0x0000e2f8 <+428>: bl 0x1f484 <android_audio_legacy::ALSADevice::isProxyDeviceOpened()>
   0x0000e2fc <+432>: cmp r0, #0
   0x0000e300 <+436>: beq 0xe228 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+220>
   0x0000e304 <+440>: ldr r0, [r5, #8]
   0x0000e308 <+444>: bl 0x1f4ac <android_audio_legacy::ALSADevice::isProxyDeviceSuspended()>
   0x0000e30c <+448>: cmp r0, #0
   0x0000e310 <+452>: bne 0xe228 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+220>
   0x0000e314 <+456>: cmp r9, #0
   0x0000e318 <+460>: bne 0xe228 <android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+220>
   0x0000e31c <+464>: mov r0, r8
   0x0000e320 <+468>: bl 0x8e70
   0x0000e324 <+472>: ldr r0, [r5, #8]
   0x0000e328 <+476>: add r1, sp, #32
   0x0000e32c <+480>: add r2, sp, #36 ; 0x24
   0x0000e330 <+484>: bl 0x1ed28 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)>
   0x0000e334 <+488>: subs r6, r0, #0

Dump of assembler code for function android_audio_legacy::ALSADevice::readFromProxy(void**, long*):
   0x0001ed28 <+0>: push {r4, r5, r6, r7, r8, r9, r10, r11, lr}
   0x0001ed2c <+4>: sub sp, sp, #20
   0x0001ed30 <+8>: mov r4, r0
   0x0001ed34 <+12>: mov r11, r1
   0x0001ed38 <+16>: str r2, [sp, #12]
   0x0001ed3c <+20>: bl 0x1eb48 <android_audio_legacy::ALSADevice::initProxyParams()>
   0x0001ed40 <+24>: mov r0, r4
   0x0001ed44 <+28>: bl 0x1ebe4 <android_audio_legacy::ALSADevice::startProxy()>
   0x0001ed48 <+32>: subs r6, r0, #0
   0x0001ed4c <+36>: bne 0x1efc4 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+668>
   0x0001ed50 <+40>: ldr r7, [pc, #808] ; 0x1f080 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+856>
   .......................................................

   0x0001ee64 <+316>: cmp r6, r3
   0x0001ee68 <+320>: strhi r3, [r4, #224] ; 0xe0
   0x0001ee6c <+324>: bl 0x9320
   0x0001ee70 <+328>: mov r1, r0
   0x0001ee74 <+332>: ldr r0, [r4, #184] ; 0xb8
   0x0001ee78 <+336>: cmp r0, #0
   0x0001ee7c <+340>: beq 0x1f068 <android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+832>
   0x0001ee80 <+344>: ldr r2, [r4, #180] ; 0xb4
=>   0x0001ee84 <+348>: bl 0x8f78

 

根据在同一个库文件中的extOutThreadFunc()和readFromProxy(...)的保存寄存器压栈个数和局部变量压栈字节,可以确认调用栈和数据栈的正确性。

本例的保存寄存器已经在数据栈中做了标注。
而且可以得到audio.primary.msm8960.so库的重定位偏移:

relocation offset of audio.primary.msm8960.so: 40fb8e88 - 0x1ee88 = 0x40F9A000.

从而调用栈如下:
#00 pc 0000e29c /system/lib/libc.so memcpy(...)
#01 pc 40fb8e88 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::ALSADevice::readFromProxy(void**, long*)+352) lr
#02 pc 40fa8334 /system/lib/hw/audio.primary.msm8960.so (android_audio_legacy::AudioHardwareALSA::extOutThreadFunc()+488) lr

对应ALSADevice::readFromProxy源码如下:

2008ssize_t  ALSADevice::readFromProxy(void **captureBuffer , ssize_t *bufferSize) {
2020    struct pcm * capture_handle = (struct pcm *)mProxyParams.mProxyPcmHandle;
2073    void *data  = dst_address(capture_handle);
2074    //TODO: Return a pointer to AudioHardware
2075    if(mProxyParams.mCaptureBuffer == NULL)
2076        mProxyParams.mCaptureBuffer =  malloc(mProxyParams.mCaptureBufferSize);  /* NG, no malloc success test */
2077    
memcpy(mProxyParams.mCaptureBuffer, (char *)data, mProxyParams.mCaptureBufferSize);  !!!crash!!!
2079    mProxyParams.mX.frames -= mProxyParams.mFrames;

 

在memcpy中r0, r1, r2用来传参,大部分实现版本在copy过程中r0-r2会被修改,r0,r1会增加,r2会减少。

r10 is used for source address advance validity detection in every copy loop.

可以通过其汇编实现考察,多数情况下r0会被压栈保存。可以结合memcpy caller一起来获取更多信息。

本版本的memcpy会把{r0, r9, r10, lr}压栈,从而可知保存的目标buffer首地址。

本例中,从栈上得到r0的初始值为0x4180a010;很难从ALSADevice::readFromProxy(...)获得其它参数信息。

出错的指令是,ldr r3, [r10],使用r10探测一下源buffer界限是否还有效。

所以是源buffer不够长或者字节数太大。更多地,

r2 0x0c00 bytes will be copied in current copy loop.
r0 - r0_saved = 4180a190 - 4180a010(saved on stack) = 0x0180 bytes has been copied to destination.


Source buffer size is less than 0x280 less than 0xc00, and leads to the buffer violate access.

Reference:
use the minimum size as argument size to avoid crash.

(2)

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***

Build fingerprint:

pid: 309, tid: 27139, name: mediaserver >>> /system/bin/mediaserver <<<

signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 41be1000

r0 44f91c08 r1 41be0c40 r2 001d4c00 r3 00000000

r4 40e83863 r5 43415998 r6 00000640 r7 001d4c00

r8 000004b0 r9 00000000 sl 41be1000 fp 4081dec9

ip 00007030 sp 43bfcb80 lr 00000408 pc 4028171c cpsr 20000010

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 46737365636f7270 d17 3d203120656d6172

d18 696f72646e612074 d19 656d6143513a3a64

d20 6d61657274536172 d21 776569766572705f

d22 7365636f72703a3a d23 7765697665725073

d24 3ff009bb63fc01c8 d25 000000000000374c

d26 0000000000000000 d27 0000000000000000

d28 0000000000000000 d29 0000000000003b66

d30 00000000000035bb d31 00000000000035ab

scr 60000010

backtrace:

#00 pc 0001871c /system/lib/libc.so

#01 pc 00000404 <unknown>

stack:

43bfcb40 ffffffff

43bfcb44 00000000

43bfcb48 fffffff0

43bfcb4c 43bfcba4 [stack:27139]

43bfcb50 4187de80

43bfcb54 00000001

43bfcb58 001d4c00

43bfcb5c 00000640

43bfcb60 001d4c00

43bfcb64 000004b0

43bfcb68 43bfcbd4 [stack:27139]

43bfcb6c 4081de4d /system/lib/libcameraservice.so

43bfcb70 4081dec9 /system/lib/libcameraservice.so

43bfcb74 4027af31 /system/lib/libc.so (dlcalloc+44)

43bfcb78 df0027ad

43bfcb7c 00000000

#00 43bfcb80 44f7e008

........ ........

#01 43bfcb80 44f7e008  r0

43bfcb84 43bfcbd4 [stack:27139]   r9

43bfcb88 4081de4d /system/lib/libcameraservice.so   r10

43bfcb8c 40e7ade3 /system/lib/hw/camera.msm8960.so (android::CustemedFace::processFrame(camera_memory*)+114)    lr

43bfcb90 43415998

43bfcb94 43bfcbd4 [stack:27139]

43bfcb98 002bf200

43bfcb9c 42f12308

43bfcba0 43bfcc70 [stack:27139]

43bfcba4 42f12340

43bfcba8 40e8ad44 /system/lib/hw/camera.msm8960.so

43bfcbac 00000043

43bfcbb0 00000030

43bfcbb4 40e743b3 /system/lib/hw/camera.msm8960.so (android::QCameraStream_preview::processPreviewFrameWithDisplay(mm_camera_ch_data_buf_t*)+1306)

43bfcbb8 00000000

43bfcbbc 00000000

memory near r0:

44f91be8 00000000 00000000 00000000 00000000

44f91bf8 00000000 00000000 00000000 00000000

44f91c08 00000000 00000000 00000000 00000000

memory near r1:

41be0c20 ffffffff ffffffff ffffffff

同样可以看出backtrace有问题,从0001871c /system/lib/libc.so可以知道问题发生在memcpy()中且

   0x0001871c <+220>: ldr r3, [r10]
同样是源buffer探测指令处。源buffer长度小于第三参数。

backtrace:

#00 pc 0001871c /system/lib/libc.so

#01 pc 40e7ade3 /system/lib/hw/camera.msm8960.so (android::CustemedFace::processFrame(camera_memory*)+114)

该栈打印出的地址好像有点错误,与反汇编出的代码地址不符。

r0_current - r0_saved = 0x44f91c08 - 0x44f7e008 = 0x13C00

r1_current  0x41be0c40

r2 001d4c00

 

588void CustemedFace::processFrame(camera_memory_t *mem) {

589    size_t size;

590    int width, height;

592    if (checkAndSetProcessingFrame()) {

593        // set the size of the gray scale map for the color format YUV420SP

594        size = (mem->size * 2) / 3;

596

597        // Avoid using mParameters.getPreviewSize as the parameter get / set is not safty in OS layer

598        // Add protection before calloc memory for mLuminanceMap

599        width = mQualcommCameraHardware->mPreviewWidth;

600        height = mQualcommCameraHardware->mPreviewHeight;

601

602        if (size == (size_t)(width * height)) {

604            // allocate the gray scale map to process

605            mLuminanceMap = (unsigned char *) calloc(size, sizeof(unsigned char));

606            if (mLuminanceMap) {

607                // copy the luminance from the frame with color format YUV420SP

608                memcpy(mLuminanceMap, (uint8_t *) mem->data, size);

(3)

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
Build fingerprint:

pid: 166, tid: 946, name: Binder_2  >>> /system/bin/mediaserver <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 40217000
    r0 40216ff0  r1 4149eb0c  r2 fffff670  r3 0000000f
    r4 400e1230  r5 ffffffff  r6 4149e1fd  r7 00000000
    r8 400e10d8  r9 fffffffd  sl 4031ba6c  fp 00000001
    ip e0000000  sp 4215ab30  lr 00000000  pc 402d9240  cpsr a0000010
    d0  ae4c01642bc9b676  d1  f3d8a10701d62264
    d2  51d1c9c899b526b5  d3  2c4466025d9d9d23
    d4  1c1965106cb060dd  d5  ef57a9e63c0f8a7b
    d6  f58ae0ebc8c7e486  d7  e7abcebee67d0fed
    d8  00000000003cff3f  d9  0000000000000000
    d10 0000000000000000  d11 0000000000000000
    d12 0000000000000000  d13 0000000000000000
    d14 0000000000000000  d15 0000000000000000
    d16 ffffffffffffffff  d17 ffffffffffffffff
    d18 ffffffffffffffff  d19 ffffffffffffffff
    d20 ffffffffffffffff  d21 ffffffffffffffff
    d22 ffffffffffffffff  d23 ffffffffffffffff
    d24 3ff01272163691fc  d25 0000000000000000
    d26 0000000000000000  d27 0000000000000000
    d28 0000000000000000  d29 0000000000000000
    d30 0000000000000000  d31 0000000000000000
    scr 20000010

backtrace:
    #00  pc 0000e240  /system/lib/libc.so
    #01  pc 000509d1  /system/lib/libmedia.so (android::AutoDetect::addString(char const*, int)+60)
    #02  pc 000bc047  /system/lib/libstagefright.so (android::ID3::getEncodingSuggestion() const+58)
    #03  pc 000bc263  /system/lib/libstagefright.so (android::ID3::ID3(android::sp<android::DataSource> const&, long long)+66)

这个调用栈是对的。

stack:
         4215aaf0  00000000 
         4215aaf4  00000000 
         4215aaf8  4215ab50  [stack:946]
         4215aafc  40935e67  /system/lib/libstagefright.so (android::ID3::Iterator::findFrame()+190)
         4215ab00  4215ab50  [stack:946]
         4215ab04  40935e67  /system/lib/libstagefright.so (android::ID3::Iterator::findFrame()+190)
         4215ab08  00000000 
         4215ab0c  4097c772  /system/lib/libstagefright.so
         4215ab10  00000000 
         4215ab14  00000000 
         4215ab18  00000000 
         4215ab1c  4215ab50  [stack:946]
         4215ab20  4215ab68  [stack:946]
         4215ab24  4215abf4  [stack:946]
         4215ab28  df0027ad 
         4215ab2c  00000000 
    #00  4215ab30  40216741   r0
         4215ab34  4038a9d5  /system/lib/libmedia.so (android::AutoDetect::addString(char const*, int)+64) lr
    #01  4215ab38  4215abf4  [stack:946]          r4
         4215ab3c  4215ab4c  [stack:946]             r5
         4215ab40  00001f40                                   r6
         4215ab44  4093604b  /system/lib/libstagefright.so (android::ID3::getEncodingSuggestion() const+62) lr
    #02  4215ab48  00000000 
         4215ab4c  ffffffff 
         4215ab50  4215abf4  [stack:946]
         4215ab54  00000000 
         4215ab58  000061ea 
         4215ab5c  400e1230 
         4215ab60  4149e1fc 
         4215ab64  0000000a 
         4215ab68  400e1230 
         4215ab6c  4215abf4  [stack:946]
         4215ab70  400e1230 
         4215ab74  40936267  /system/lib/libstagefright.so (android::ID3::ID3(android::sp<android::DataSource> const&, long long)+70)
    #03  4215ab78  00000000 
         4215ab7c  400e10b8 
         4215ab80  400e10c8 
         4215ab84  408ddcb7  /system/lib/libstagefright.so (android::MP3Extractor::MP3Extractor(android::sp<android::DataSource> const&, android::sp<android::AMessage> const&)+594)

1141void AutoDetect::addString(const char* str, int numBytes) {
1142    // No need to store strings unless we will attempt to detect a two-byte encoding.
1143    if (str != NULL && mLocaleEncoding & ~kOneByteEncodings) {
1144        if (mAddedStringSize < mAddedStringLen + numBytes) {
1145            // Grow space
1146            while (mAddedStringSize < mAddedStringLen + numBytes) {
1147                mAddedStringSize += 128;
1148            }
1149            mAddedStrings = (char*)realloc(mAddedStrings, mAddedStringSize);
1150        }
1151
1152        if (mAddedStrings) {
1153           
memcpy(mAddedStrings + mAddedStringLen, str, numBytes); 
1154            mAddedStringLen += numBytes;
1155        }
1156    }
1157}

From the call trace and source code, the root cause is
When the MediaExtractor try to extract mp3 ID3 tag information, it encounters the SIGSEGV:SEGV_MAPERR crash when doing memcpy.

Dump of assembler code for function android::AutoDetect::addString(char const*, int):
   0x00050994 <+0>: push {r4, r5, r6, lr}
   0x00050996 <+2>: mov r4, r0
   0x00050998 <+4>: mov r6, r1
   0x0005099a <+6>: mov r5, r2

   0x000509ca <+54>: mov r1, r6
   0x000509cc <+56>: adds r0, r3, r2
   0x000509ce <+58>: mov r2, r5
   0x000509d0 <+60>: blx 0x3abb4

r4-r6 are not changed until crash occurs, so use current register value.
this pointer : r4 400e1230 
src_buf str  : r6 4149e1fd
numBytes   : r5 ffffffff 

Notice the {r0, lr} pushed by memcpy on the stack
    #00  4215ab30  40216741 
         4215ab34  4038a9d5
r0 is the start address of destination in memcpy. dst_buf = 40216741.

So, memcpy(dst=0x40216741, src=0x4149e1fd, size_t num=0xffffffff) with invalid arg numBytes -1 which is promoted to unsigned int 0xffffffff.

The memcpy starts and encounters the unmapped destination page.
r0 40216ff0  r1 4149eb0c  r2 fffff670  r3 0000000f
r0 40216741->40216ff0->40217000(fault addr).

r0_current - r0_saved = 0x40216ff0 - 0x40216741 + 1 = 0x8B0
r1_current - r1_saved = 0x4149eb0c - 0x4149e1fd + 1 = 0x910

[reference solution]
Add if(numBytes>0) statement.

[END]

 

你可能感兴趣的:(memcpy,LR)