我在我的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
我找不到有关如何解密此输出的任何信息。每个应用程序启动时,每行显示的数字都在变化。我希望有一种方法可以使用这些信息作为腐败发生地点的线索,因为我无法从代码中找到它。我也尝试使用“-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):
任何事情,对要检查的典型事项的建议或仅仅使用malloc调试信息的方式都会有很大的帮助,谢谢!
答案 0 :(得分:10)
malloc调试属性可能在您分配的区域之前和之后设置一些幻数。然后,当释放时,它会检查那些区域以确保幻数仍在那里。
例如,如果分配1024个字节:
char * p = malloc(1024);
malloc调试代码实际上会分配您请求的1024个字节,还有一些额外的字节:
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
^ 0xc0000000 ^ 0xc0000020
然后,库会将魔术值写入这32个字节:
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[ 0xdeadd00d | | 0xdeadd00d ]
^ 0xc0000000 ^ 0xc0000020
图书馆会将0xc0000020
返回p
,内部会保存0xc0000000
,尺寸等。
然后,您的函数以某种方式使用分配的区域:
memset(p, 0, 1025);
请注意,此行复制了超过1024个字节。这会将0写入最后32个字节的魔术区域(注意最后32个字节中的0
,应该是0xdeadd00d
):
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[ 0xdeadd00d | 000... ...00 | 0x0eadd00d ]
^ 0xc0000000 ^ 0xc0000020 (address)
当你的函数免费调用时:
free(p);
然后,库将检查以确保第一个和最后32个字节仍为0xdeadd00d
。由于你的函数覆盖了最后32个字节,它会打印出你发布的错误。
这只是malloc调试检查如何工作的一个例子。如果您想确切了解malloc调试检查的内容及其工作原理,请转到Android源的bionic
目录并搜索您设置的属性libc.debug.malloc
。
检查代码,了解在被调用函数中如何使用已分配的内存。你可能正在写你所分配区域之外的区域。
答案 1 :(得分:3)
对我而言:
我的Android应用程序的原生部分中的段错误,此时void函数返回其调用者。
表示堆栈损坏(超过堆损坏)。什么状态存储在你正在返回的这个函数的堆栈中(以及它调用的每个函数......)?
您看到的调用堆栈输出应该是检测到损坏时堆栈上每个函数的地址。您需要知道您的库的加载地址,以便将这些地址映射回.so
中的符号。 (我认为这个问题会有所帮助:How to use addr2line in Android)
81258188
在堆栈转储顶部重复的事实也表明你可能已经烧掉了堆栈的底部(通过递归过多次)。如果您不知道代码中有任何故意递归,那么找出加载库的位置并将其映射回代码可能很有用。