0

I have a program where I use a lot of mallocs (and other similar functions) to allocate memory for different datatypes. As we know this functions may fail. How can I write a neat code for checking if memory was successfully allocated, and if not, freeing all the previous mallocs, if any?

I thought maybe writing a function that frees every pointer I malloc, if they are != NULL. But then I will need to send a lot of parameters. Any better ideas?

Thanks.

3 Answers3

2

This is actually a non-trivial C coding idiom question. One answer is to learn C++ and use auto_pointer.

In C, I've had success with the following idiom.

  1. Set all pointers to NULL upon declaration.
  2. Allocate memory only as it's needed.
  3. If an allocation fails, set an error value and goto a label at the end where all pointers are freed.
  4. If for some reason you need to free a pointer early, set it NULL again.
  5. All normal executions must fall through to the end so that everything is freed (no intermediate return).

It ends up looking like this:

int err = 0;
FOO *p = NULL; 
BAR *q = NULL; 
BAZ *r = NULL;

p = malloc(...);
if (!p) {
  err = P_MALLOC_FAILURE;
  goto done;
}
....
q = malloc(...);
if (!q) {
  err = Q_MALLOC_FAILURE;
  goto done;
}
....
// Done with p.  Free it early.
free(p);
p = NULL;
....
done:
  free(p);
  free(q);
  return err;

The definition of free ensures nothing happens if a pointer is still NULL at the end. If you don't like the repeated code, you can abuse a macro:

#define ALLOC_OR_FAIL(P) do { \
  P = malloc(sizeof *P); \
  if (!P) { \
    err = P ## _MALLOC_FAILURE; \
    goto done; \
  } } while (0)
Twonky
  • 796
  • 13
  • 31
Gene
  • 46,253
  • 4
  • 58
  • 96
  • I've seen this idiom, but then enclosed in its entirety by a `do .. while(0)` block, for the sole reason one could avoid `goto` and use `break` instead. (But the net effect - and possibly, the generated code - is the same.) – Jongware Sep 09 '14 at 22:40
0

Well, you could design your code in such a way that if there is an error then your program flow works its way back up the call stack and all your functions free their allocated memory when they are returning an error condition.

If your code is not that well organized, then the only portable way to "neatly" free all the previous mallocs is if you store a global table of mallocs as you do them, that you keep up to date every time you call malloc or free (or any other allocating function).

However, modern operating systems free all the memory for you on process exit, and in fact they can do this a lot faster than you can because they can just free the entire process's memory allocation in one go. IMHO a practical decision would be to just exit without explicitly freeing unless you suspect that your code will be run on a system where that would leak memory.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Also, for "neatly" dealing with the issue your program will have to handle the fact that the functions that needed that memory failed. I only have seen in chunks of code where there are BIG mallocs (so, the risk of running out of memory is big, and worth the extra effort to control). Otherwise, if you do not handle it, your program may do odd things. Usually, an elegant "Out of memory" log and an exit is the best option. – SJuan76 Sep 09 '14 at 21:36
  • 1
    What? Global table of mallocs? Exit without freeing? – JoeManiaci Sep 09 '14 at 21:37
  • I'm sorry but I can't believe anyone would actually suggest not cleaning up their pointers. If someone is not willing to keep track of, and clean up their memory the proper way, then they should just use a language that has automatic cleanup. – JoeManiaci Sep 10 '14 at 16:54
  • @JoeManiaci can you explain the advantage of making multiple `free` calls immediately proior to exit, when on an operating system which would free all resources associated with a process when that process exits? See [this answer](http://stackoverflow.com/a/2213836/1505939) for a realistic use-case. – M.M Sep 10 '14 at 20:31
  • @Matt: Oh I don't know, how about an app that is meant to be run 24/7 for months on end and because you choose not to free memory when necessary, you eventually run out of memory because of your long running memory leak. And no, that is not a realistic use-case. Who cares about the efficiencies of closing a program? Even if you did care, his example would be an extremely rare edge case. And even if you did care and it wasn't rare, a good designer would choose a slight slowdown over a potential system crash. Hell, look at the guy who posted right below that guy. – JoeManiaci Sep 10 '14 at 21:20
  • @Matt: And that guy made another point that I too have ran into; Sockets not being closed. So no, the OS doesn't clean up everything you think it would. Now if you're making a simple little test program, where you maybe have a handful of memory allocations, sure, very little damage could be done. However, it's just not a good habit to have. – JoeManiaci Sep 10 '14 at 21:22
  • @JoeManiaci "how about an app that is meant to be run 24/7 for months on end and because you choose not to free memory when necessary, you eventually run out of memory because of your long running memory leak." - that has nothing to do with anything I've said. There is no long running memory leak. There is no potential crash associated with exiting a process without freeing memory first. Also, `malloc` and `free` have nothing to do with sockets being closed. – M.M Sep 11 '14 at 00:47
  • lol, have you ever used pointers? By definition, not freeing memory allocated to your process is a memory leak. Regardless of whether or not the OS cleans up everything a 100%. It will if you're using an integer pointer to hold your socket. – JoeManiaci Sep 11 '14 at 15:51
  • @JoeManiaci If 100% is cleaned up then there is no leak, by definition. By your logic any process that has not yet exited has leaked memory. – M.M Sep 11 '14 at 20:05
  • Go here: http://en.wikipedia.org/wiki/Memory_leak and read the first sentence. If say you enter a function and allocate memory, then leave that same function without free()ing the memory, that memory is no longer able to be used by either your program, or any other program running on the machine. So I should have clarified a little better, so long as you are able to still access the pointer to allocated memory, it's good. If you no longer have access to the pointer though, you no longer have access to the memory allocated to it. Not too many useful programs however only have main(). – JoeManiaci Sep 12 '14 at 16:33
  • You're looking at memory leaks using the system as a whole, sure, the OS will almost always clean up 100% of whatever was allocated to your process. If that's all you're looking for, sure, no memory leak. But that's not the right way to look at it. – JoeManiaci Sep 12 '14 at 16:36
  • @JoeManiaci memory can be allocated in one function and freed from another function. Nowhere am I suggesting that the program allocate memory and then not hold any pointers to that memory. – M.M Sep 12 '14 at 23:28
0

Just like pzaenger said...

ptr = calloc/malloc/realloc(parameters);

if(ptr == NULL)
{
    printf("Well shucks...");
}

Simple enough.

I've been building on some code and I too have a lot of parameters to it 7/8 at the moment, with most of them being pointers that are dereferenced and so on.

I have a few functions, with more on the way, that use these same 7/8 parameters. So to clean them up, I am simply going to stuff them into a structure(c struct). That way, all I have to do is pass a single parameter, the struct(or more than likely a ptr to the struct).

All you have to do now at the beginning, is malloc/calloc memory for the struct, then malloc/calloc memory for any pointers inside the struct.

Then you pass that struct to and fro, doing whatever it is you need to do.

In the end, you go through the struct and free up any memory malloc/calloc'ed inside of it. Then free up the memory(if a ptr to the struct was used) for the struct itself.

JoeManiaci
  • 435
  • 3
  • 15