Memory 使用android ndk进行内存损坏调试
当一个void函数返回给它的调用者时,我的android应用程序的本机部分出现了一个segfault。为了更好地可视化,我在被调用方函数的末尾放了一条log语句,在调用方函数中放了一条log语句,就在调用被调用方之后(很抱歉这个双关语)。 在logcat中,会打印第一条消息,而不会打印第二条消息(应用程序崩溃) 考虑到可能的内存损坏,我决定激活malloc调试(在adb shell中给出“setprop libc.debug.malloc 10”)。然后,在被调用函数末尾的日志消息之后,我在logcat中得到了以下信息:Memory 使用android ndk进行内存损坏调试,memory,memory-management,android-ndk,Memory,Memory Management,Android Ndk,当一个void函数返回给它的调用者时,我的android应用程序的本机部分出现了一个segfault。为了更好地可视化,我在被调用方函数的末尾放了一条log语句,在调用方函数中放了一条log语句,就在调用被调用方之后(很抱歉这个双关语)。 在logcat中,会打印第一条消息,而不会打印第二条消息(应用程序崩溃) 考虑到可能的内存损坏,我决定激活malloc调试(在adb shell中给出“setprop libc.debug.malloc 10”)。然后,在被调用函数末尾的日志消息之后,我在lo
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):构建指纹:“google/soju/crespo:2.3/GRH55/79397:用户/发布密钥”
I/DEBUG(12311):pid:12778,tid:12907>>>com.ntrack.tunermalloc DEBUG属性可能在您分配的区域前后设置了一些幻数。然后,在释放时,它会检查这些区域以确保幻数仍然存在
例如,如果分配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
库将0xc000020
返回到p
中,并在内部保存0xc000000
、大小等。
然后,您的函数以某种方式使用分配的区域:
memset(p, 0, 1025);
请注意,此行复制了超过1024个字节。这会将0写入最后32个字节的魔法区域(请注意最后32个字节中的0
,应该是0xdeadd00d
):
当函数调用free时:
free(p);
然后,库将进行检查,以确保第一个和最后32个字节仍然是0xdeadd00d
。由于函数重写了最后32个字节,它将打印一个错误,就像您发布的一样
这只是malloc调试检查如何工作的一个示例。如果您想确切了解malloc调试检查的内容及其工作方式,请转到Android source的bionic
目录,搜索您设置的属性,libc.debug.malloc
检查代码,了解如何在被调用函数中使用分配的内存。您可能正在向分配区域之外的区域写入内容。对我来说,这是:
在我的android应用程序的本机部分,当一个void函数返回到它的调用者时,出现了一个segfault
表示堆栈损坏(比堆损坏更严重)。您从中返回的函数(以及从它调用的每个函数中返回的函数)的堆栈上存储了什么状态
您看到的调用堆栈输出应该是检测到损坏时堆栈上每个函数的地址。您需要知道加载库的地址,才能将这些地址映射回中的符号。因此(我认为这个问题会有所帮助:)
81258188
在堆栈转储的顶部重复的事实也表明您可能已经破坏了堆栈的底部(通过多次递归)。如果您不知道代码中存在任何有意的递归,那么找出库的加载位置并将其映射回代码可能会很有用。这将是大量代码:)谢谢大家的回答。在更改了之前调用的函数中的内容后,问题昨天就解决了,这影响了在某种程度上,我还没有完全理解错误函数,但我也认为它与堆栈损坏有关,因为——正如你所猜测的——函数中有一个递归部分,应该进行更深入的研究。我一检查就会回到这个问题上来。谢谢你!我犯的错误是——我想记住r一个包含100个uint32_t的数组。我调用了memAlloc(100),并使用长度为0->99的for循环写入该数组。它肯定会抛出此错误,因为我写入的内容超出了我分配的范围!memAlloc(100*sizeof(uin32_t))修复了它。希望这对某人有所帮助!
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[ 0xdeadd00d | 000... ...00 | 0x0eadd00d ]
^ 0xc0000000 ^ 0xc0000020 (address)
free(p);