【问题标题】:Memory corruption debug with android ndk使用 android ndk 调试内存损坏
【发布时间】:2012-07-05 05:09:58
【问题描述】:

我的 android 应用程序的本机部分出现段错误,此时 void 函数返回其调用者。为了更好地可视化,我在被调用者函数的末尾放置了一条日志语句,并在调用者函数中放置了一条日志语句,就在调用被调用者之后(对不起双关语)。 在 logcat 中,第一条消息被打印,第二条则没有(应用程序崩溃)。

考虑到可能的内存损坏,我决定激活 malloc 调试(在 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 调试信息的方式都会有很大帮助,谢谢!

【问题讨论】:

  • 那会是很多代码:)

标签: memory memory-management android-ndk


【解决方案1】:

对我来说,这是:

我的 android 应用程序的本机部分出现段错误,此时 void 函数返回其调用者。

表示堆栈损坏(不仅仅是堆损坏)。您从(以及它调用的每个函数..)返回的这个函数的堆栈中存储了什么状态?

您看到的调用堆栈输出应该是检测到损坏时堆栈上每个函数的地址。您需要知道您的库加载到的地址,以便将这些地址映射回.so 中的符号。 (我认为这个问题会有所帮助:How to use addr2line in Android

81258188 在堆栈转储顶部重复的事实也表明您可能已经炸毁堆栈底部(通过递归太多次)。如果您不知道代码中有任何有意的递归,那么找出您的库的加载位置并将其映射回您的代码可能会很有用。

【讨论】:

  • 谢谢大家的回答。在更改了一个更早调用的函数后,问题昨天消失了,这以我尚未完全理解的方式影响了故障函数的行为,但我也认为它与堆栈损坏有关,因为 - 正如你所猜测的- 函数中有一个递归部分,应该更深入地研究。我一检查就会回来。
【解决方案2】:

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

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

【讨论】:

  • 谢谢!我犯的错误是 - 我想为 100 个 uint32_t 的数组 memAlloc。我调用了 memAlloc(100),并使用长度为 0->99 的 for 循环写入数组。它一定会抛出这个错误,因为我写的超出了我分配的内容! memAlloc(100*sizeof(uin32_t)) 修复了它。希望这对某人有帮助!
猜你喜欢
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-10-27
相关资源
最近更新 更多