tags:

views:

65

answers:

4

Hi All,

why the below code gives me error of "double free or corruption"... when i compile and run with gcc [(Debian 4.4.4-8) 4.4.5 20100728 (prerelease)]. Thanks in advance!

#include <stdio.h>
#include <stdlib.h>

typedef struct
{
 int *index1;
} data;

void doo(int *);

int main(int argc, char *argv[])
{
 int *a = (int *) malloc(10*sizeof(int));
 int i;

 for(i=0; i<10; i++)
 {
  a[i] = 2*i;
 }

 doo(a);

 data one;
 one.index1 = a;

 printf("%d\n", one.index1[4]);

 free(a);

 printf("%d\n", one.index1[4]);

 free(one.index1);
 return 0;
}

void doo(int *b)
{
 b = (int *) realloc(b, 5*sizeof(int));
 return;
}
+1  A: 

Because the storage pointed to by 'a' and 'one.index1' are the same (assignment before the first printf). Thus you have a double free.

Darron
How can I get a copy of "a" stored in "one.index1" not the pointer?
jkl
A: 

You are passing to doo a pointer. You modify the pointer itself, but your main function does not get the new address.

Benoit
Not the reason for the "double free", but worth correcting
pmg
How can I get a copy of "a" stored in "one.index1" not the pointer?
jkl
@pmg, OP is shrinking allocated memory space. Why would that cause any relocation or change of address?
Kedar Soparkar
Guessing how it works internally is not a reason to produce bad code! Implementation could change.
Benoit
I have to hurry now, can't check the Standard ... I'm pretty sure it allows realloc() to move the objects under any conditions
pmg
+2  A: 
one.index1=a;
...
free(a);
...
free(one.index1);
...

Ergo, the double free.

void doo(int *b)
{
 b = (int *) realloc(b, 5*sizeof(int));
 return;
}

When you pass the a pointer to this function, its value(which is infact an address), gets copied into b, another local int pointer. Now, when you realloc space for 5 ints, it changes the space allocation for a infact. So your space gets reduced from 10 to 5 ints.

As requested by OP, to get the same data & separate memory pointers, space must be allocated afresh for the new pointer, as a pointer is after all, just a variable, holding an address. If you allocate two separate blocks, you would get two separate addresses, which can be freed individually.

Kedar Soparkar
How can I get a copy of "a" stored in "one.index1" not the pointer?
jkl
a has an address. This address gets copied to one.index1. So, now both have the same address. If you perform a free() on one, the space allocated from that address onwards is freed. If you try to free the same space again, you will encounter an error.
Kedar Soparkar
So is there anyway to say it to clone "a", and assign that clone to "one.index1"? So that both "a" and "one.index1" will have the same data, but separate memory pointer.
jkl
@crypto, no it is not hw!
jkl
Kedar Soparkar
A: 

That happens because you make one.index1 and a point to the same memory location.

To test this add the following to your code:

 one.index1 = a; // from now on, both variables point to the same address

 printf("-> 0x%x\n", one.index1);
 printf("-> 0x%x\n", a);

 printf("%d\n", one.index1[4]);

 free(a); // release the resource pointed by a

 // You should not try to print the data of one.index1[4] since 
 // that piece of memory doesn't exist no more. 
 printf("%d\n", one.index1[4]); 

 free(one.index1); // Problem: trying to free the same memory resource TWICE.

You'll notice that both pointers will print the same memory addresses. So after free(a); is executed, performing free(one.index1); is redundant, and trying to free a resource that is not allocated anymore is what is causes the problem.

karlphillip
You can't print an address with the "%x" format specifier and expect a reasonable output on all systems. Use "%p" format specifier and cast the address to `void*` *(and don't expect a reasonable output on all systems)*.
pmg
@pmg Thank you. You can print it as you like.
karlphillip