使用android ndk调试内存损坏

ath*_*hos 2 memory memory-management android-ndk

我在我的android应用程序的本机部分中获得了一个段错误,此时void函数返回其调用者.为了更好地可视化,我在被调用者函数的末尾添加了一个日志语句,在调用者函数的一个函数中,在调用被调用者之后(对于双关语抱歉).在logcat中,打印第一条消息,第二条消息打印(应用程序崩溃).

考虑到可能的内存损坏我决定激活malloc debug(在adb shell中给出"setprop libc.debug.malloc 10").然后,我在来自被调用函数结束的日志消息之后的logcat中得到这个:

D/MyApp - NativeSide(12778):  I am the callee function and I am about to return!
E/libc    (12778): *** FREE CHECK: buffer 0x82869900 corrupted 16 bytes before allocation
E/libc    (12778): call stack:
E/libc    (12778):  0: 8000e3ea
E/libc    (12778):  1: 8000e49c
E/libc    (12778):  2: 8000e4e2
E/libc    (12778):  3: 8000e540
E/libc    (12778):  4: afd14ccc
E/libc    (12778):  5: 81258188
E/libc    (12778):  6: 81258188
E/libc    (12778):  7: 81258188
E/libc    (12778):  8: 81258188
E/libc    (12778):  9: 81258188
E/libc    (12778): 10: 81258188
E/libc    (12778): 11: 81258188
E/libc    (12778): 12: 81258188
E/libc    (12778): 13: 81258188
E/libc    (12778): 14: 81258188
E/libc    (12778): 15: 81258188
E/libc    (12778): 16: 81258188
E/libc    (12778): 17: 81258188
E/libc    (12778): 18: 81258188
E/libc    (12778): 19: 81258188
Run Code Online (Sandbox Code Playgroud)

我找不到有关如何解密此输出的任何信息.每个应用程序启动时,每行显示的数字都在变化.我希望有一种方法可以使用这些信息作为腐败发生地点的线索,因为我无法从代码中找到它.我也尝试使用"-fstack-check标志构建本机库,但我不能说我是否在日志中有更多信息(似乎没有,但我可能已经错过了它们),或者我是否需要做其他事情得到他们.

此外,这是堆栈转储,在"FREE CHECK:"消息之后.

I/DEBUG   (12311): *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
I/DEBUG   (12311): Build fingerprint: 'google/soju/crespo:2.3/GRH55/79397:user/release-keys'
I/DEBUG   (12311): pid: 12778, tid: 12907  >>> com.ntrack.tuner <<<
I/DEBUG   (12311): signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr deadbaad
I/DEBUG   (12311):  r0 deadbaad  r1 45ea374c  r2 00000027  r3 00000000
I/DEBUG   (12311):  r4 00000080  r5 45ea374c  r6 8003422e  r7 45ea37b4
I/DEBUG   (12311):  r8 45da4000  r9 a811eca5  10 00100000  fp 00000001
I/DEBUG   (12311):  ip ffffffff  sp 45ea3738  lr 8000f623  pc 8000f650  cpsr 20000030
I/DEBUG   (12311):  d0  3f9664f48406d639  d1  3f8226e3e96e8495
I/DEBUG   (12311):  d2  3faba1ba1bb34201  d3  0000000000000000
I/DEBUG   (12311):  d4  3d7943379e56fd24  d5  3d8f940585cd5f95
I/DEBUG   (12311):  d6  3f2cf2145b888497  d7  3f2cf214636d85f8
I/DEBUG   (12311):  d8  0000000000000000  d9  0000000000000000
I/DEBUG   (12311):  d10 0000000000000000  d11 0000000000000000
I/DEBUG   (12311):  d12 0000000000000000  d13 0000000000000000
I/DEBUG   (12311):  d14 0000000000000000  d15 0000000000000000
I/DEBUG   (12311):  scr 20000010
I/DEBUG   (12311):
Run Code Online (Sandbox Code Playgroud)

任何事情,对要检查的典型事物的建议或只是使用malloc调试信息的方式都会有很大的帮助,谢谢!

小智 10

malloc调试属性可能在您分配的区域之前和之后设置一些幻数.然后,当释放时,它会检查那些区域以确保幻数仍在那里.

例如,如果您分配1024个字节:

char * p = malloc(1024);
Run Code Online (Sandbox Code Playgroud)

malloc调试代码实际上会分配您请求的1024个字节,还有一些额外的代码:

[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
^ 0xc0000000    ^ 0xc0000020
Run Code Online (Sandbox Code Playgroud)

然后,库会将魔术值写入这32个字节:

[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[  0xdeadd00d   |                           | 0xdeadd00d    ]
^ 0xc0000000    ^ 0xc0000020
Run Code Online (Sandbox Code Playgroud)

该库将返回0xc0000020p并在内部它会保存0xc0000000,大小等你函数,则使用分配的区域以某种方式:

memset(p, 0, 1025);
Run Code Online (Sandbox Code Playgroud)

请注意,此行复制了超过1024个字节.这会将0写入最后32字节魔术区域(注意0最后32个字节,应该是0xdeadd00d):

[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[  0xdeadd00d   |  000...             ...00 | 0x0eadd00d    ]
^ 0xc0000000    ^ 0xc0000020  (address)
Run Code Online (Sandbox Code Playgroud)

当您的函数免费调用时:

free(p);
Run Code Online (Sandbox Code Playgroud)

然后,库将检查以确保第一个和最后32个字节仍然存在0xdeadd00d.由于你的函数覆盖了最后32个字节,它会打印出你发布的错误.

这只是malloc调试检查如何工作的一个例子.如果您想确切了解malloc调试检查的内容及其工作原理,请转到bionicAndroid源目录并搜索您设置的属性libc.debug.malloc.

检查代码,了解如何在被调用函数中使用已分配的内存.您可能正在写入您分配区域之外的区域.