Tips and Tricks to avoid memory leaks in writing C
3 comments
A common issue for people coming from garbage-collected languages is to be very aware of what happens when you malloc() inside a function and return a pointer. Someone is going to have to free it! One common pattern is to have this malloc()ing be restricted to an obviously named foo_init() function, and then pair it with a foo_free() function that gets passed the relevant data structure, and frees anything that the _init() function malloc()ed. You then keep the _init() and _free() functions together and update them in parallel, so all the malloc()s in one are paired with a corresponding free() in the other.
"Exceptions" can be useful: lots of my code looks like
int fd = -1;
char *buf = NULL
if ((fd = open("/foo", O_RDONLY, 0)) == -1)
goto err;
if ((buf = malloc(1024)) == NULL)
goto err;
...
return 0;
err:
if (fd =! -1)
close(fd);
free(buf);
return -1;Nice idea, but people would scream seeing those goto's.
I used to do those in a macro/function like,
#define memalloc(x,y) { x=0;if(x=malloc(y)){}else{printf("error:no mem");} }
#define memalloc(x,y) { x=0;if(x=malloc(y)){}else{printf("error:no mem");} }
a simple and efficient method for finding memory leaks is replacing malloc/free with house-keeping macros when debugging:
#include <stdlib.h>
#include <stdio.h>
void *(*_malloc_old) (size_t size) = malloc;
void (*_free_old) (void *ptr) = free;
#define malloc(size) _malloc_new (size, __FUNCTION__, __LINE__)
#define free(ptr) _free_new (ptr)
struct alloc
{
const char *function;
int line;
void *ptr;
struct alloc *next;
};
struct alloc *list = NULL;
void *_malloc_new (size_t size, const char *function, int line)
{
struct alloc *e = _malloc_old (sizeof *e);
void *ptr = _malloc_old (size);
e->function = function;
e->line = line;
e->ptr = ptr;
e->next = list;
list = e;
return (ptr);
}
void *_free_new (void *ptr)
{
struct alloc *prev = NULL, *e = list;
while (e) {
if (e->ptr == ptr) {
break;
}
prev = e;
e = e->next;
}
if (e) {
if (e == list) {
list = NULL;
}
if (prev) {
prev->next = e->next;
}
_free_old (e);
}
_free_old (ptr);
}
void pallocs (FILE *f)
{
struct alloc *e = list;
while (e) {
fprintf (f, "%s:%d\t0x%x\n", e->function, e->line, (size_t)e->ptr);
e = e->next;
}
}
int main ()
{
void *ptr = malloc (1024);
void *leak = malloc (1024);
void *leak2 = malloc (1024);
printf ("before free:\n");
pallocs (stdout);
printf ("after free:\n");
free (ptr);
pallocs (stdout);
}
outputs: before free:
main:67 0x9dab860
main:66 0x9dab440
main:65 0x9dab020
after free:
main:67 0x9dab860
main:66 0x9dab440
Like,
1. not assigning null to a pointer after freeing it
2. not allocating enough memory for string processing
Please throw in your tips and tricks to avoid memory leaks and memory related problems.