Thread: Realloc Double Free

  1. #1
    Registered User
    Join Date
    Aug 2008
    Posts
    3

    Realloc Double Free

    Hello,

    I have been writing a library in C. For the strings part, I use realloc. I have been testing it and, when adding characters to a string, the first few characters work. But, after a few characters, realloc gives me a double free error. Being a C newbie I am probably just misusing the function. Some help here please.

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Provide the smallest and simplest compilable program that demonstrates the error.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Aug 2008
    Posts
    3

    The Code

    Quote Originally Posted by laserlight View Post
    Provide the smallest and simplest compilable program that demonstrates the error.
    Code:
    typedef String char;
    String* String_new(){
    	String *self=calloc(1, sizeof(char));
    	self[0]='\0';
    	return self;
    }
    
    void String_addChar(String *self, char ch){
    	if(ch=='\0'){//If the character is NULL
    		return;//Exit function
    	}
    	int len=strlen(self);
    	self=realloc(self, sizeof(char)*len+2);
    	char buffer[]={ch,'\0'};
    	strcat(self,buffer);
    }
    
    String* String_readFile(FILE* file){
    	String *buffer=String_new();
    	char current=fgetc(file);
    	while(current!=EOF){
    		String_addChar(buffer,current);
    		current=fgetc(file);
    	}
    	return buffer;
    }
    
    FILE* file=fopen("hello.txt","r");
    String *f=String_readFile(file);
    fclose(file);
    free(f);

  4. #4
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    It's "typedef char String", but I guess you've got that right in your code. You're also missing headers and a main(), without which nothing much happens.

    But when I add those in, nothing happens. That is, I don't get any runtime errors. So, try, try again.

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > typedef String char;
    > String* String_new(){
    > String *self=calloc(1, sizeof(char));
    You create a typedef, then don't use it.
    If you change the type away from char, then calloc will still allocate a char. At that point, the code is broke.

    > self=realloc(self, sizeof(char)*len+2);
    1. If realloc fails, it returns NULL. This trashes the original pointer. If that's your only copy of the pointer, you have a memory leak.
    2. realloc can MOVE the memory. Which in this case is a problem for you, since the caller doesn't get to find out about the change. So the next time you call this function, you're passing the OLD value of self again, which realloc will try to free (and hence, this is your double free).
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    Quote Originally Posted by Salem View Post
    > typedef String char;
    > String* String_new(){
    > String *self=calloc(1, sizeof(char));
    You create a typedef, then don't use it.
    If you change the type away from char, then calloc will still allocate a char. At that point, the code is broke.

    > self=realloc(self, sizeof(char)*len+2);
    1. If realloc fails, it returns NULL. This trashes the original pointer. If that's your only copy of the pointer, you have a memory leak.
    2. realloc can MOVE the memory. Which in this case is a problem for you, since the caller doesn't get to find out about the change. So the next time you call this function, you're passing the OLD value of self again, which realloc will try to free (and hence, this is your double free).
    If realloc moves memory, it DOESN'T affect anything at all - except OTHER pointers, if you have any, that point to data being realloc()ed. In this case, he has only one pointer, he always gives realloc() proper pointer and allways stores what realloc returns into same pointer. Realloc() & free() usage is fine here. This code works, I tested it on itself (renamed file.c into hello.txt). I only enclosed readFile(), fclose() & free() in main() into
    Code:
    if (file) {}
    block - so you don't get to call free() if fopen() failed.
    Last edited by rasta_freak; 08-02-2008 at 06:15 PM.

  7. #7
    Registered User
    Join Date
    Aug 2008
    Posts
    3

    Smile Thanks

    Thanks for all of the help. I have implemented the changes and it works fine. Thanks!

  8. #8
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    @rasta_freak
    > String *buffer=String_new();
    This is the original pointer.

    > String_addChar(buffer,current);
    This makes a copy of the pointer.

    > self=realloc(self, sizeof(char)*len+2);
    If this moves the memory, then buffer in the caller will NOT CHANGE.

    > This code works, I tested it on itself (renamed file.c into hello.txt).
    I'm sure it does for you. But did you test the case when realloc moved the pointer?

    Sure, if the last call to malloc is the one you keep realloc'ing in a simple program, then it's going to be able to extend it a long way before moving it. The illusion of "success" whilst still being bugged.

    But put it in a larger program, where other things are using malloc, and watch what happens.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  9. #9
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    Quote Originally Posted by Salem View Post
    @rasta_freak
    > String *buffer=String_new();
    This is the original pointer.

    > String_addChar(buffer,current);
    This makes a copy of the pointer.

    > self=realloc(self, sizeof(char)*len+2);
    If this moves the memory, then buffer in the caller will NOT CHANGE.

    > This code works, I tested it on itself (renamed file.c into hello.txt).
    I'm sure it does for you. But did you test the case when realloc moved the pointer?

    Sure, if the last call to malloc is the one you keep realloc'ing in a simple program, then it's going to be able to extend it a long way before moving it. The illusion of "success" whilst still being bugged.

    But put it in a larger program, where other things are using malloc, and watch what happens.
    addChar() doesn't make a copy of pointer, it operates on SAME pointer you got from calloc() in newString(). It gives realloc old "self" pointer, and gets from it a new "self" pointer (old may get invalid but nobody cares - memory/buffer stays the same, even if moved, and it's address is in "self" pointer before and after realloc()). IN ANY CASE, THIS WORKS. Even in enterprise level software, THIS WILL WORK. This code is valid, and you Salem, recheck realloc() man pages, please... You can realloc() something malloc()ed or calloc()ed freely - they use same/similar allocation methods. Only important thing is to have a SINGLE pointer to data being malloc()-ed/realloc()-ed, which is normaly a case anyway (you generate other pointers if needed out of 1st which is always valid). AND to use "x=realloc(x, new_size);" form, of course (which he uses).
    Last edited by rasta_freak; 08-03-2008 at 04:47 AM.

  10. #10
    The larch
    Join Date
    May 2006
    Posts
    3,573
    What you don't realize is that addChar indeed receives a copy of the pointer. This copied pointer points to the same string, so modifications to the string are visible to the calling code. However, modifications to the pointer itself - when the address it is pointing to is changed - are not visible to the calling code.

    By the way:
    Code:
    typedef String char;
    Could there be a more awful and misleading typedef? Since when is char a String?
    I might be wrong.

    Thank you, anon. You sure know how to recognize different types of trees from quite a long way away.
    Quoted more than 1000 times (I hope).

  11. #11
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    > addChar() doesn't make a copy of pointer, it operates on SAME pointer you got from calloc() in newString().
    OK, quick lesson, since you obviously have no clue.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void func ( char *p ) {
        p = malloc( 12 );
        strcpy( p, "hello world" );
    }
    
    int main(void)
    {
        char *p = NULL; // or calling String_new() to initialise it
        func( p );  // or calling String_addChar() to expand and add data
        printf( "&#37;s\n", p );    // you're saying this works?
        return 0;
    }
    At least the OP was switched on enough to realise that String_new() had to return a pointer. The only thing lacking was the bit of detail about realloc moving the whole block. So String_addChar() also needs to be capable of returning a modified pointer.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  12. #12
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    Quote Originally Posted by Salem View Post
    > addChar() doesn't make a copy of pointer, it operates on SAME pointer you got from calloc() in newString().
    OK, quick lesson, since you obviously have no clue.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    void func ( char *p ) {
        p = malloc( 12 );
        strcpy( p, "hello world" );
    }
    
    int main(void)
    {
        char *p = NULL; // or calling String_new() to initialise it
        func( p );  // or calling String_addChar() to expand and add data
        printf( "&#37;s\n", p );    // you're saying this works?
        return 0;
    }
    At least the OP was switched on enough to realise that String_new() had to return a pointer. The only thing lacking was the bit of detail about realloc moving the whole block. So String_addChar() also needs to be capable of returning a modified pointer.
    Ok, don't need to test it - i get it know. Didn't see it on previous reading - I heavily use realloc() but store pointers in struct so they are all updated ok (for this same reason, ironicly...). Yes, addChar() works on local copy of pointer and it's bad. It doesn't update original. Sorry Salem, i was too quick on words...
    Anyway, fix is:
    Code:
    void String_addChar(String **p, char ch){
    	if(ch=='\0'){//If the character is NULL
    		return;//Exit function
    	}
    	int len=strlen(*p);
    	*p=realloc(*p, sizeof(char)*len+2);
    	char buffer[]={ch,'\0'};
    	strcat(*p,buffer);
    }
    - and call addChar(&buffer, current)
    Last edited by rasta_freak; 08-03-2008 at 05:36 AM.

  13. #13
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Much better
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  14. #14
    Registered User
    Join Date
    Jul 2008
    Posts
    133
    Quote Originally Posted by Salem View Post
    Much better
    Thanks. I guess i was hanging too much on Balkan forums...

  15. #15
    Registered User
    Join Date
    Mar 2008
    Posts
    43
    This was mentioned earlier but heres an example of realloc and not destroying your previous pointer ( so you can avoid bad free()'s and memory leaks ):

    Code:
    char * add_space(char ** str)
    {
    	int len = strlen(*str);
    	char * tmp = (char *)realloc(*str, sizeof(char)*len+2);
    	if(tmp)
    	{
                    /* allocation was ok so we have our new address to point to */
    		*str = tmp;
    	} else {
    		/* out of memory, so do something... or not */
    		free(*str);
    	}
    
    	/* now you can error check the function on NULL or not */
    	return tmp;	
    }
    Hope that helps.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. double free or corruption (fasttop)
    By yougene in forum C Programming
    Replies: 6
    Last Post: 01-17-2009, 06:44 PM
  2. Need some help...
    By darkconvoy in forum C Programming
    Replies: 32
    Last Post: 04-29-2008, 03:33 PM
  3. Malloc - Free giving double free or corruption error
    By andrew.bolster in forum C Programming
    Replies: 2
    Last Post: 11-02-2007, 06:22 AM
  4. C++ to C Conversion
    By dicon in forum C Programming
    Replies: 7
    Last Post: 06-11-2007, 08:38 PM
  5. Please HELP!!
    By traz in forum C++ Programming
    Replies: 4
    Last Post: 04-14-2003, 09:20 PM