0

I am currently debugging a Project I've been working on for a while, and have encountered some crazy errors involving free. I can't upload the code, because there is no way to tell exactly where the problem lies (about 2500 lines of code split into 22 files), but I will explain what I know.

To start with, gdb is being used for the whole debugging process. The error seems to rise from a call to free. I get the following error message from gdb, after the program exits with SIGABRT:

*** Error in `application': free(): invalid next size (normal): 0x08052008 ***
======= Backtrace: =========
/lib/i386-linux-gnu/libc.so.6(+0x767e2)[0xb7e467e2]
/lib/i386-linux-gnu/libc.so.6(+0x77530)[0xb7e47530]
application[0x8049aef]
application[0x804a8aa]
application[0x8048bee]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf5)[0xb7de9935]
application[0x8048a51]
======= Memory map: ========
08048000-08050000 r-xp 00000000 00:16 1571817    application
08050000-08051000 r--p 00007000 00:16 1571817    application
08051000-08052000 rw-p 00008000 00:16 1571817    application
08052000-08073000 rw-p 00000000 00:00 0          [heap]
b7d9c000-b7db7000 r-xp 00000000 08:01 1309022    /lib/i386-linux-gnu/libgcc_s.so.1
b7db7000-b7db8000 r--p 0001a000 08:01 1309022    /lib/i386-linux-gnu/libgcc_s.so.1
b7db8000-b7db9000 rw-p 0001b000 08:01 1309022    /lib/i386-linux-gnu/libgcc_s.so.1
b7dce000-b7dd0000 rw-p 00000000 00:00 0 
b7dd0000-b7f7d000 r-xp 00000000 08:01 1308997    /lib/i386-linux-gnu/libc-2.17.so
b7f7d000-b7f7f000 r--p 001ad000 08:01 1308997    /lib/i386-linux-gnu/libc-2.17.so
b7f7f000-b7f80000 rw-p 001af000 08:01 1308997    /lib/i386-linux-gnu/libc-2.17.so
b7f80000-b7f83000 rw-p 00000000 00:00 0 
b7f83000-b7fc4000 r-xp 00000000 08:01 1309045    /lib/i386-linux-gnu/libm-2.17.so
b7fc4000-b7fc5000 r--p 00040000 08:01 1309045    /lib/i386-linux-gnu/libm-2.17.so
b7fc5000-b7fc6000 rw-p 00041000 08:01 1309045    /lib/i386-linux-gnu/libm-2.17.so
b7fd9000-b7fdd000 rw-p 00000000 00:00 0 
b7fdd000-b7fde000 r-xp 00000000 00:00 0          [vdso]
b7fde000-b7ffe000 r-xp 00000000 08:01 1308973    /lib/i386-linux-gnu/ld-2.17.so
b7ffe000-b7fff000 r--p 0001f000 08:01 1308973    /lib/i386-linux-gnu/ld-2.17.so
b7fff000-b8000000 rw-p 00020000 08:01 1308973    /lib/i386-linux-gnu/ld-2.17.so
bffdf000-c0000000 rw-p 00000000 00:00 0          [stack]

It seems to be like a common double-free, yet there is more. I have the tendency to set all global pointers to NULL when they don't contain anything, so even if I double-freed it wouldn't cause an error. Moreover, as my application deals with data encryption, I created two functions of my own that first overwrite the memory and then call free.

Can this problem be caused by reading from memory that is out of bounds? For example, if I have a 64-byte memory block and accidentally try to read the 65th byte, will this cause an error when calling free? I know that writing out of bounds, even if not immediately, causes an error...

I've been trying to locate the bug all day, but with no success. Are there any tools (apart from breaks, step, continue and watches) that gdb provides for my case? Can I see what my code really does in terms of memory allocation and management? For example, is there any way to see how much memory is actually allocated in a position pointed to by a specific pointer?

Thank you in advance for your time! :)

someone
  • 361
  • 2
  • 3
  • 13
  • Can you show related code? – Grijesh Chauhan Jul 31 '13 at 17:16
  • As I said, the problem arises at a specific part of my application, but might be caused at any point. I checked again and again that part and it works fine. Only when working as a whole, the program crashes. I can't upload 22 files! :D – someone Jul 31 '13 at 17:18
  • "Can this problem be caused by reading from memory that is out of bounds?" definitely yes, I have seen this happen quite often – Ingo Leonhardt Jul 31 '13 at 17:18
  • 4
    Have you already tried using `valgrind`? I would suspect you are writing to freed memory or writing beyond an allocated buffer. – jxh Jul 31 '13 at 17:19
  • I've checked both possibilities; unfortunately, either this is not the case or locating the bug is beyond my powers... What is `valgrind`? – someone Jul 31 '13 at 17:21
  • 3
    "*I've been trying to locate the bug all day ...*" as an irrational advise: Take a break, a good meal, either a nice movie or your girl/boy and then have a sleep .. and only then start over with debugging, preferable using Valgrind. ;-) – alk Jul 31 '13 at 17:24
  • Sounds good, but I finally have to complete this project! :D – someone Jul 31 '13 at 17:25

2 Answers2

5

This intensly smells like a corrupted memory management due to having overwritten unallocated memory.

You might like to use Valgrind to analyse this.

alk
  • 69,737
  • 10
  • 105
  • 255
  • Could you elaborate on valgrind? – someone Jul 31 '13 at 17:22
  • Valgrind observes your program by running it in a sandbox. Tomorrow you might like to read here: http://valgrind.org/docs/manual/QuickStart.html – alk Jul 31 '13 at 17:25
  • Is it available in the Ubuntu repositories or am I asking for too much? – someone Jul 31 '13 at 17:28
  • @angel: I'm not using Ubuntu, but it's available for Debian, so the Ubuntu rep should provide it. – alk Jul 31 '13 at 17:29
  • Thanks again for introducing Valgrind! I used it and found the MAJOR error: I forgot to initialize a memory block and (indirectly) continued writing out of the allocated space... However, Valgrind still gives me another 50 errors described as: `Conditional jump or move depends on uninitialised value(s)`. Paradoxically, the conditional looks like: `if (i == positions[j]) {i++; j++;}` Both `i` and `j` are initialized (inside a for-loop). Array `positions` was filled before, values checked using gdb. I compiled the code without optimizations (-O0). The program works, but what could be wrong? – someone Aug 02 '13 at 10:11
  • @angel: You might have copied values to `positions` from a source which hadn't been properly initialised. However: Did you use the `--track-origins=yes` option? – alk Aug 02 '13 at 10:16
  • That's how I call it: `valgrind --track-origins=yes --leak-check=full --show-reachable=yes application`. – someone Aug 02 '13 at 10:25
  • @angel: "*What could be wrong?*": Valgrind is telling you what's wrong: `Conditional jump or move depends on uninitialised value(s)` ;-) You won't get around to keep on searching, using standard debugging technics, like cutting down the code to the bare minimum, by successivly excluding part by part of it. – alk Aug 02 '13 at 10:35
  • Is there any way it tell me which of those variables is affected? At the moment, it only reports the line... – someone Aug 02 '13 at 13:06
  • 1
    @angel: Try adding line breaks to the line in question so that every variable sits on its own line. C does not care about line breaks. Then do recompile. – alk Aug 03 '13 at 08:31
  • 1
    Thanks for all your help! I finished debugging, all errors were corrected! This Valgrind was actually right... `positions` has 64 values and when the last value is popped (works like a stack) I was accessing `positions[64]` which is indeed un-initialized. Didn't cause a problem originally, but could have been disastrous had it not been found... Thanks again!!! – someone Aug 03 '13 at 13:48
  • 1
    ... It should have given me an `invalid read` message, though... ;) – someone Aug 03 '13 at 13:49
  • @angel: Another off-by-one bug again, a bit hidden, but however some things never change ...!-) – alk Aug 03 '13 at 15:59
1

@alk has already answered, but I am adding this FYI as another culprit of misbehaving free functions:

If the pointer to an allocated memory block has moved to a different location: e.g.

  char *string;
  string = malloc(10);
  string++;      //move memory pointer to location other than originally allocated  
  free(string);  //attempt to free will result in error

free is attempting to free a pointer no longer pointing to what was allocated, and will always throw an error.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Oh, thanks. I only use pointers with the [] operator. Can it still cause a problem? – someone Aug 01 '13 at 06:46
  • @angel - I typically only match free calls to malloc or calloc calls using any kind of pointer. Wehn I use something such as – ryyker Aug 01 '13 at 17:43
  • @angel - Sorry, kept getting errors on the last attempt. What are you using free for? Can you give me an example? I have never used free for anything created using [], that;' because rather than dynamic allocation, these are statically defined. No free is necessay. – ryyker Aug 01 '13 at 18:01
  • I'm sorry, I should have explained better. You probably misunderstood. All freed pointers are first allocated using `malloc`. I use the [] operator to access the data they point to. Due to that, there is no possibility that I change a pointer by accident, is there? :D – someone Aug 02 '13 at 09:43
  • I made some progress using valgrind (I was writing after the allocated space by ONE BYTE!), yet the errors are in the most crazy places... – someone Aug 02 '13 at 09:46
  • For example: `int *sth = (int *)malloc(size); sth[0] = 1; /* that is what I mean */` – someone Aug 02 '13 at 09:48
  • 1
    @angel: Do not cast `malloc/calloc/realloc()`, as in C it's not necessary nor recommended! – alk Aug 02 '13 at 10:21
  • @angel - regarding changing the pointer when accessing the variable using its index (i.e. '[]') such as string[0] or string[1], string[i++] - its not likely that you are changing the pointer this way. Only if you do something like string++. The first way you are accessing a location within memory, the other you are moving the pointer itself. Your issue is likely caused by something else. I am curious to see what alk will say. – ryyker Aug 02 '13 at 23:37
  • @angel: Please see this answer: http://stackoverflow.com/a/605858/694576 for why not to cast malloc() & friends in C. – alk Aug 03 '13 at 15:56