views:

159

answers:

4

I have these structs:

typedef struct _Frag{
  struct _Frag *next;
  char *seq;
  int x1; 
  int length;  
}Frag;

typedef struct _Fragment{ 
  int type; 
  Frag *frag_list;   
}Fragment;

And then I created a array

Fragment *fragments=malloc(1,sizeof(Fragment)); // or more
fragments->frag_list=malloc(1,sizeof(Frag)); // or more
Frag *frag=malloc(10,sizeof(Frag));
frag->seq="test str\n";
...
frag->next=malloc(1,sizeof(Frag));
frag->next->seq="test str\n";

At the end of program, I want to free the memory, the function is:

static void free_frags(){
  int i;
  Fragment *fragment;
  Frag *current,*next;
  for(i=0;i<1;i++){
    fragment=&snp_frags[i];
    current=fragment->frag_list;
    next=current->next;

    while(next!=NULL){
      free(current->seq);
      //free(current->next);
      free(current);
      current=next;
      next=current->next;
    }
    free(current->seq);
    //free(current->next);
    free(current);
    //free(fragment->frag_list);
    free(&snp_frags[i]);
  }
  free(snp_frags);
}

If I use valgrind to debug it, valgrind says that:

=============================================
==3810== Invalid read of size 4
==3810==    at 0x80490FD: free_snp (hap.c:16)
==3810==    by 0x80493AF: main (hap.c:73)
==3810==  Address 0x41b139c is 12 bytes inside a block of size 296 free'd
==3810==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==3810==    by 0x8049167: free_snp (hap.c:30)
==3810==    by 0x80493AF: main (hap.c:73)
==3810== 
==3810== Invalid free() / delete / delete[]
==3810==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==3810==    by 0x8049167: free_snp (hap.c:30)
==3810==    by 0x80493AF: main (hap.c:73)
==3810==  Address 0x41b1398 is 8 bytes inside a block of size 296 free'd
==3810==    at 0x4023EBA: free (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==3810==    by 0x8049167: free_snp (hap.c:30)
==3810==    by 0x80493AF: main (hap.c:73)

And please help me to fix these errors, thanx.

+7  A: 

In

frag->seq="test str\n";

you haven't malloc'ed the memory block - the string is allocated in static storage - and later you try to free() that memory block. You can only free() blocks allocated with malloc(), otherwise you risk running into undefined behaviour.

You could either only put pointers to statically allocated strings into Frag::seq fields and never free() them or you could malloc() memory for these strings and copy the strings into malloc'ed blocks.

sharptooth
A: 

You seemed to be saying that you are freeing this memory as the last thing the program does.

Why bother? Why not just exit? Then your deallocation will be perfect, and faster.

Update: I never said this was always a perfect practice. In specialized environments like certain primitive embedded systems it might be important, certainly not on Windows or Unix/Mac, where doing this right before exit is considered bad practice. And it obviously doesn't hurt for the one developer to perfect his code. That's obvious.

For those of you commenting who really seem to believe this can leak memory, I guess you should never ^C your program. Reboot after every ^C, segfault or other debugging termination. Never kill anything with a task manager, or kill(1).

Everything commenters mentioned is in fact cleaned up. I do know one thing that isn't always cleaned up, which no one mentioned: temporary files.

DigitalRoss
I didn't downvote, but I consider it good practice to free your memory before exiting. OSes don't have to do a good job of cleaning it up for you.
Chris Lutz
Terrible advice. While it might be the case on your platform that the OS will grab the memory back anyway, this practice can't extend any further. What about resources? Not just memory, but an open file, or open network connection. You can't just "let it go", because now you're permanently hogging resources other programs can't use. Strive for correctness, and consistency.
GMan
Then he or someone else copy-pastes this code into a production system and gains a nice memory leak. That won't do.
sharptooth
@GMan: The OS will also release those resources. It's true that you shouldn't rely on it (See sharptooths comment) though.
Kristof Provost
Your OS might, there exist OS's where unreleased memory could remain so.
GMan
@everyone: I guess you would also downvote the STL library for the following statement in the FAQ: "In most environments, this would be highly counterproductive; free would typically have to touch many long unreferenced pages just before the operating system reclaims them anyway. It would often introduce a significant delay on program exit, and would possibly page out large portions of other applications. There is nothing to be gained by this action, since the OS reclaims memory on program exit anyway, and it should do so without touching that memory." =)
Zed
@Zed - That's C++. This is C. C (arguably) runs on more exotic systems than C++, and expects a lot less of it's operating system, and puts a lot more responsibility on the programmer's shoulders.
Chris Lutz
For standard apps freeing memory right before exiting is ridiculous. All it does is slow down the exiting by a massive margain. I can't think of a single OS that doesn't get back the resources that a program opened, and I doubt another person can either. That's the entire point of an OS. It's why they were made. It's why they're still made.Freeing before exiting is only applicable if your program resides in memory, eg a device driver, or to aid you in debugging something.
Pod
Imagine two programs that do the same thing, using a heap, but one is C and the other C++. I say the heaps will end up in similar states, because the two programs allocated and freed about the same memory in about the same order. Please tell me how in any tiny way the logic behind the STL FAQ's "highly counterproductive" warning will apply to one heap but not the other virtually identical one? And please note that I'm not arguing for bad code, just bringing up a performance consideration you seem unwilling to even recognize.
DigitalRoss
digitalross KNOWS WHAT HE IS TALKING ABOUT. There is a depressing prevalence of programmers who say "always free memory" with zeal; yes it's a good habit but under typical circumstances, freeing all allocated memory at exit hurts performance.
Artelius
@GMan: "What about resources? Not just memory, but an open file [...]" - the C99 standard states that calling `exit()` will fush and close all open streams; as always you can be as sloppy as you like *as long as you know what you're doing!*
Christoph
PS: I'd consider an OS which doesn't reclaim resources on program termination broken: there's always the possibility of unexpected abortion (or do you only write bug-free code? never produced a segfault?) so the OS can't assume that programs clean up after themselves!
Christoph
If your program uses shared memory or shared synchronization objects, you should at least deal with those.
bk1e
+1  A: 
  1. You're frequently calling molloc() instead of malloc(). Check your vowels.
  2. You're calling malloc() with the wrong number of arguments - it only takes one.
  3. You can't assign strings - that performs pointer assignment, which is not what you want. You have to use strcpy() or strncpy() or memcpy(), depending on your religious perspective on the whole *cpy() mess, to copy the contents of one string into another.
Chris Lutz
A: 

remove the code line "free(fragment)". It will work well.

Charlie Epps