Reputation: 1281
I am getting a segfault in the native part of my android app, in the moment a void function returns to its caller. To visualize better, I put a log statement at the end of the callee function, and one in the caller function, right after the call to the callee (sorry for the pun). In the logcat, the first message is printed, and the second not (the app crashes).
Thinking about a possible memory corruption I decided to activate malloc debug (giving "setprop libc.debug.malloc 10" in adb shell). Then, i get this in the logcat right after the log message from the end of the callee function:
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
I couldn't find any information on how to decipher this output. The numbers shown at each line are changing at every app launch. I hope there's a way to use this information as a clue on where the corruption happens, as I can't find it from the code. I also tried building the native libraries with the "-fstack-check flag, but I couldn't say if I got more informations in the log (it seems not but I might have missed them), or whether I need to do other things to get them.
Also, here's the stack dump, coming after the "FREE CHECK:" message.
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):
Anything, a suggestion on the typical things to check or just the way to make use of the malloc debug informations would be of great help, thanks!
Upvotes: 3
Views: 14480
Reputation: 25177
To me, this:
a segfault in the native part of my android app, in the moment a void function returns to its caller.
means stack corruption (more than heap corruption). What state is stored on the stack of this function you're returning from (and from every function it calls ..)?
The call stack output you're seeing should be the address of each function on the stack at the time the corruption was detected. You'll need to know what address your library was loaded at to map those back to a symbol in your .so
. (I think this question will help: How to use addr2line in Android)
The fact that 81258188
repeats off the top of the stack dump also suggest that you might've blown out the bottom of the stack (by recursing too many times). If you're not aware of any intentional recursion in your code, then figuring out where your library was loaded and mapping that back to your code could be useful.
Upvotes: 3
Reputation: 227
The malloc debug property is probably setting some magic numbers before and after the area you allocate. Then, when freeing, it would check those areas to make sure the magic number is still there.
For example, if you allocate 1024 bytes:
char * p = malloc(1024);
The malloc debug code would actually allocate 1024 bytes that you requested, plus some extra around it:
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
^ 0xc0000000 ^ 0xc0000020
The library would then write a magic value into those 32 bytes:
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[ 0xdeadd00d | | 0xdeadd00d ]
^ 0xc0000000 ^ 0xc0000020
The library would return 0xc0000020
into p
and internally it would save 0xc0000000
, the size, etc.
Your function then uses the allocated area somehow:
memset(p, 0, 1025);
Notice this line copied more than 1024 bytes. That would write a 0 into the last 32 byte magic area (notice the 0
in the last 32 bytes, which should be 0xdeadd00d
):
[ 32 bytes ---- | -------- 1024 bytes ------| ---- 32 bytes ]
[ 0xdeadd00d | 000... ...00 | 0x0eadd00d ]
^ 0xc0000000 ^ 0xc0000020 (address)
When your function calls free:
free(p);
The library would then check to make sure the first and last 32 bytes are still 0xdeadd00d
. Since your function overwrote the last 32 bytes, it would print an error like you posted.
This is only an example of how a malloc debug checking would work. If you would like to see exactly what the malloc debug checks and how it works, go to the bionic
directory of Android source and search for the property you set, libc.debug.malloc
.
Check your code for how you use allocated memory in the called function. You are probably writing to an area outside of the area you allocated.
Upvotes: 11