![]() |
sponsored links |
|
|
sponsored links
|
|
1
13th March 00:38
External User
Posts: 1
|
I don't have any experience with the free command and don't understand
structures and it eventually used up all memory and all swap space before the OS killed it. So, now I'm going through it and trying to fix all the leaks. The basic approach I'm taking is to list all the routines I use that return pointers (I call them allocators) and make sure that every routine that calls an allocator either returns the pointer returned by the allocator (either directly or as a component of something it does return or indirectly, by side effects) or else calls another routine to free the pointer. I'm going through the list, one allocator at a time, and grepping to find out every place it is called and freeing what it returns when that is warranted. This is not an unpleasant activity and, in the process, I'm finding lots of functions that seemed like a good idea at the time but which in fact are never called, and commenting them out. On the other hand, I don't really know the effect that these efforts to free pointers are really having. So, as an experiment, I wrote some sample code, included below, intended to test the approach I'm taking. I ran it and I find it inconclusive. First let me show you the code and then I'll explain what the problem is. #include <stdio.h> struct measured_list { int length_of_list; int * list_of_int; }; struct measured_list * alloc_ml(int n, int * l) { int i; struct measured_list *ml; ml = (struct measured_list *) malloc(sizeof(struct measured_list)); ml->length_of_list = n; ml->list_of_int = (int *) malloc(n*sizeof(int)); for(i=0;i<n;i++) ml->list_of_int[i] = l[i]; return ml; } void free_ml(struct measured_list **ml) { int i; free((*ml)->list_of_int); free(*ml); return; } struct measured_list * copy_ml(struct measured_list * ml) { int i,n,*l; struct measured_list * new_ml; n = ml->length_of_list; l = ml->list_of_int; new_ml = alloc_ml(n,l); return new_ml; } int main() { int i,l[3]={2,3,7}; /* printf("ml1->list_of_int[0] = %d\n",ml1->list_of_int[0]); */ ml1 = alloc_ml(3,l); ml2 = copy_alloc(ml1); ml3 = copy_alloc(ml2); free_ml(&ml1); free_ml(&ml2); free_ml(&ml3); printf("ml1->list_of_int[0] = %d\n",ml1->list_of_int[0]); return 0; } If I uncomment the line containing the first printf statement, I get a segmentation fault, because the array of three integers ml1->list_of_int hasn't been allocated yet. That's what I'm used to. If the same thing happened with the printf statement following free_ml(&ml3), I'd be convinced that the space was really unallocated and available for recycling. But instead, it prints out garbage. So, I'm unconvinced and confused. If you can think of a better test of whether this memory is really available for reuse, I'd be glad to know about it. Hmmm, now that I think about it, another approach occurs to me: I can write a for loop that keeps generating copies of ml1, like the Sorcerer's Apprentice, and choose the number of iterations by experiment until it is so large that the program gets killed after using up all the memory and swap space. Then modify the loop so that it frees the preceding copy with free_ml after it generates the new one, and tell it to print out the last one, and see whether the program still dies and whether I can make the number of iterations even larger. I'll try that after I log out. Just in case it is the wrong approach, or there is a better way, I'll still post this and look forward to your comments. Since this is a discussion group for C, and not one for Linux, I won't tell you that I am doing this on a PC running RH 7.1 Linux. -- Ignorantly, Allan Adler <ara@zurich.csail.mit.edu> * Disclaimer: I am a guest and *not* a member of the MIT CSAIL. My actions and * comments do not reflect in any way on MIT. Also, I am nowhere near Boston. -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
|
2
13th March 04:22
External User
Posts: 1
|
....
I believe adding a line in free_ml (before return like:*ml = NULL; will get you the seg-fault cheers -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
3
13th March 08:11
External User
Posts: 1
|
I suggest you use a tool like IBM Rational Purify. It can tell you how much
memory you have leaked and where you allocated that memory. If you aks nicely it can also tell you if you ever read from storage which has never which bits of your code are unused. Some parts of academia can get Purify for free on the IBM Scholars Program which was at http://ibm.com/university the last time I looked, but that was over 3 years ago now. There's also a free (gratis and libre) tool called Valgrind which I'm told can do the some of the same things on Linux, but I never got the hang of it. -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
4
13th March 08:11
External User
Posts: 1
|
You're basing the invitation to let yourslef be convinced on incorrect
assumptions. There is no such thing as a right to get a segfault. What your code does is cause undefined behaviour. You can't expect undefined behaviour to come in some particular flavour --- that's why it's called "undefined". -- Hans-Bernhard Broeker (broeker@physik.rwth-aachen.de) Even if all the snow were burnt, ashes would remain. -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
5
13th March 08:11
External User
Posts: 1
|
On 29 Sep 2006 08:35:37 GMT, Allan Adler <ara@nestle.csail.mit.edu>
Don't cast the return from malloc. Doing so caused the compiler to suppress a diagnostic which would have alerted you to the fact the your forgot to include stdlib.h. As it is coded now, it invokes undefined behavior because a C89 compiler is required to erroneously assume that malloc returns an int. Where are ml1, ml2, and ml3 defined? This invokes undefined behavior because ml1 has been freed. No, you invoked undefined behavior because ml1 is not initialized. Fortunately, the undefined behavior resulted in something that got your immediate attention. Undefined behavior is not required to be convenient or consistent. In this case, it chose to do something other than what you expected. Having expectations for undefined behavior is not reasonable. The C standard requires the value of a freed pointer to become indeterminate. Any attempt to evaluate an indeterminate value invokes undefined behavior. Basically there is no way in standard C to verify that free did what it was supposed to. Even if there were a way to determine whether a particular piece of memory was available, how could you tell the difference between: 1 - free failing and the memory not available for future use. 2 - free succeeding and the memory available but some other process grabbing the memory before you could test it. Remove del for email -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
6
13th March 11:36
External User
Posts: 1
|
Malloc gets the memory free returns it.
Every malloc must match to a free. Never free a pointer that was not malloc. Never change a malloced pointer, or you lose the block. -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
7
13th March 11:36
External User
Posts: 1
|
Actually it's a standard library function, not a command.
It merely makes the previously malloced (or realloced, or calloced) block of memory available for later reallocation. Think of it as returning the block to a "pool" of free memory that the malloc/realloc/calloc/ free subsystem manages. After you free a block, that pointer value is no longer valid (until it is later returned from another call to malloc/realloc/calloc). Yup, that's why free is useful. You're confusing having an address mapped into your process's virtual address space with the addressed memory being available. Once the previously allocated block (whose address became mapped into your process space as a side effect of malloc's operations) is returned via free, the storage may still lie within your process's address space, but your program is not allowed to access it *because it now belongs to the malloc/ realloc/calloc/free subsystem*. In particular, it may contain link pointers and size information (referring to other free blocks in the managed dynamic storage pool). If you mess up that internal information, you'll break the malloc/realloc/ calloc/free subsystem, which typically causes a hard to diagnose failure at some later point in the program. Although actually the segmentation fault was more likely due to ml1 having contained a null pointer value until you later assigned it a non-null malloced value. Just because storage is freed doesn't mean that previous pointers to it acquire null pointer values. (You can store ******** NULL when you deallocate them, as a safety measure.) -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
8
13th March 11:36
External User
Posts: 1
|
A little more.
You need to structure your program better. Use of unalloced pointers is always a bad idea. One way to deal with this is to set all pointers equal to NULL. You can then test for != NULL to see if it points to anything. be sure to set it back to NULL after freeing it. -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
9
13th March 11:37
External User
Posts: 1
|
Use Valgrind (Only on Linux) to findout memory leaks,
![]() It will detect invalid free, invalid read/write (which will cause Core dump) and UnFreed Memory and many more http://www.valgrind.org --raxit sheth -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|
|
10
13th March 18:25
External User
Posts: 1
|
Set your compiler to higher warning levels. Your code is not runnable as listed
and will not compile properly. Gross errors: You forgot to include the standard headers <malloc.h> and <stdlib.h>. You did not declare ml1, ml2 and ml3 prior to use in main(). You use copy_alloc() in your main(). This function does not exist. (I think you intended to write copy_ml there.) Attempting to use a pointer to freed memory is a common programmer error in C but C as such offers little protection from it. (If any.) Depending on your debugging environment, your OS and your C runtime libraries, your debugger may provide a debug version of free() that will invalidate the pointer whose memory was freed and fill the freed memory with special bytes indicating it is dead. Then if you err and try to use that pointer in debug it will point to an invalid address and seg fault or it will point to garbage and your program will fail. In release mode however, there is no such protection unless the OS does it automatically for security reasons but your C program shouldn't rely on this. In the sample case your first printf attempts to access an un-initialized pointer and the runtime catches it. In the case of the second printf the pointer ml1 is unchanged by the free() function but the contents are invalid. (Depending on the OS and the memory load, the contents may still remain but you can never know.) If you are going write your own allocators, and this is what you did in implementing alloc_ml and free_ml, then you should invalidate the pointer in the free_ml function at runtime and not rely on your OS to do it for you. In this case setting *ml = NULL should work nicely. Taking some liberties with your sample like removing unused local variables from the functions, I re-write it: #include <stdio.h> #include <stdlib.h> #include <malloc.h> struct measured_list { int length_of_list; int * list_of_int; }; struct measured_list * alloc_ml(int n, int * l) { int i; struct measured_list *ml; ml = (struct measured_list *) malloc(sizeof(struct measured_list)); ml->length_of_list = n; ml->list_of_int = (int *) malloc(n*sizeof(int)); for(i=0;i<n;i++) ml->list_of_int[i] = l[i]; return ml; } void free_ml(struct measured_list **ml) { free((*ml)->list_of_int); free(*ml); *ml = NULL; /* invalidate the pointer */ return; } struct measured_list * copy_ml(struct measured_list * ml) { int n,*l; struct measured_list * new_ml; n = ml->length_of_list; l = ml->list_of_int; new_ml = alloc_ml(n,l); return new_ml; } int main() { int l[3]={2,3,7}; struct measured_list *ml1, *ml2, *ml3; /* printf("ml1->list_of_int[0] = %d\n",ml1->list_of_int[0]); */ ml1 = alloc_ml(3,l); ml2 = copy_ml(ml1); ml3 = copy_ml(ml2); free_ml(&ml1); free_ml(&ml2); free_ml(&ml3); printf("ml1->list_of_int[0] = %d\n", ml1->list_of_int[0]); return 0; } Since free_ml sets the pointer ml to NULL the printf fails with segmentation fault as intended. This program compiles without errors or warnings and fails as designed in VC++ 6.0 on Windows and GCC 4.0.0 on Linux. Now, a word about style and design: A SIGSEGV is a catastrophic failure of your program and while it's nice to have that protection while debugging, for it to happen in production code is to demonstrate laziness or inattention. Your programs in debug mode should be designed to catch and report errors like this. Learn to use the assert macro and don't forget to include <assert.h>. Your production code should be designed to recover gracefully from errors or to properly report them so try to catch null or bad pointers in your code before attempting to use them. -- comp.lang.c.moderated - moderation address: clcm@plethora.net -- you must have an appropriate newsgroups line in your header for your mail to be seen, or the newsgroup name in square brackets in the subject line. Sorry. |
|