4

I was looking for some guidelines on the net for safely managing memory allocation/deallocation on C. But could not find some good sources.

I thought maybe it is a good idea to pile up one, maybe on this site. I could start with some, to indicate what I mean, maybe someone can "improve" it, so that we have a full list of guidelines which help us ensure (to the maximum extent) we manage memory properly.

Example :

  1. Always initialize pointers when declared.

    int*p = NULL;
    
  2. Check return type of malloc

    int *p = malloc(sizeof(int));
    if(p==NULL)
    {
      /* do some error handling*/
    }
    
  3. Each malloc should have corresponding free

  4. Possible problem is to free memory twice. How to avoid that? Assign pointer NULL after deletion.

    free(p);
    p=NULL;
    

    note: As pointed in comments, this does not protect if an object had two pointers. And it was already freed using one of the pointers.

  5. Another possible problem is to free memory which contains some garbage or free memory not allocated by malloc. How to avoid that? AFAIAC this is not easy to check. Given programmer follows previous steps, he/she should additionally check no random/bad memory gets assigned to pointer.

Otherwise, if one follows these guidelines this seems pretty safe way to manage memory for me.

Any ideas? Suggestions?

  • 1
    "pointer gets assigned some random trash memory" - could you give me any example? – ikh Mar 31 '14 at 10:36
  • @ikh: I don't know like `int*p=&x;` where `x` is stack object and then goes out of scope. Or maybe `int*p=0xfffccd` (some invalid address) –  Mar 31 '14 at 10:37
  • 3
    *malloc* returns a value not a type. Passing a null pointer to *free* is perfectly fine and will do nothing. – datenwolf Mar 31 '14 at 10:37
  • 1
    your question sounds more like the start of a discussion – AndersK Mar 31 '14 at 10:39
  • @Claptrap: Ok then we can close it or I will delete it if this was not the right place to ask :/ –  Mar 31 '14 at 10:42
  • 4
    I really think you should ask yourself why a pointer can be double deleted or have a wrong assignment during execution. My (short) experience show me that when you start to over verifying pointer validity over your code, there a huge chance that you are messing up things somewhere. It is impossible to me to be sure, but when I see a code full of `if(p != NULL) free(p)`, I keep eyes open. – wesley.mesquita Mar 31 '14 at 10:45
  • @wesley.mesquita: double deletion and wrong assignments are only pitfalls with memory management in C? (in addition to just forgetting to free malloced memory) –  Mar 31 '14 at 10:49
  • Note that the check `if (p != NULL)` before `free(p)` is useless: [an attempt to `free()` a `NULL` pointer just does nothing](http://stackoverflow.com/a/1938758/1629821) and is perfectly safe. Instead, I agree with you on setting the pointer to `NULL` after calling `free()` on it, to avoid dangling references. – Mr.C64 Mar 31 '14 at 10:51
  • 1
    @dmcr_code no. Search for the book `C Traps and Pitfalls`, by Andrew Koenig. – wesley.mesquita Mar 31 '14 at 10:52
  • @Mr.C64, asigning NULL to a pointer after free doesn't set all the *other* pointers to that data to NULL. – vonbrand Mar 31 '14 at 11:11
  • 1
    Specify the size to allocate by using the object itself rather than its (expected) type: `ptr = malloc(NELEMS * sizeof *ptr);` – pmg Mar 31 '14 at 11:12
  • @vonbrand: yes that is good point. You mean if I have two pointers to some object, and I free one? (then I can erroneously try to free the object via another one too) –  Mar 31 '14 at 11:14
  • Idea: During debug, to catch "free" and other errors, have used a wrapper for `malloc()` and `free()`. The `myfree()` prototype was `void myfree(void *ptr, size_t sz)` and would, amongst other tests, check that the size of memory thought it was freeing was in fact the same size allocated. Typically the size allocated is still known at "free" time at little cost. Further, during debug, with the original size of the `malloc()` (saved via `mymalloc()`), run-time assertions could be made for test range access. With a "release" build, the normal `malloc()` and `free()` are used. – chux - Reinstate Monica Mar 31 '14 at 14:55
  • Note: Other functions allocate memory like `realloc()`, `calloc()`, `aligned_alloc()`, `strdup()` (not standard) ... – chux - Reinstate Monica Mar 31 '14 at 15:01

2 Answers2

5

EDIT: The question has changed quite a lot, so here is a sample of the "first" question:

In this guidelines one problem I see, is if somehow after malloc and before free pointer gets assigned some random trash memory - in this case, programmer should ensure this does not happen. Otherwise free will try to free trash memory and probably crash.

Just use a const pointer!

int * const p = malloc(sizeof(int));
if(p==NULL)
{
   /* do some error handling*/
}

/* do what you want with p, but you won't be able to change its value */

free(p);

You don't need to initialize p as NULL, since malloc() returns NULL if an error occured.

You don't need to check if p is NULL, free() will check that for you.

nouney
  • 4,363
  • 19
  • 31
  • 1
    @nouney: if I use const pointer then I can *never* change it to point to smth else right? (This might not what any programmer could want in general case) –  Mar 31 '14 at 10:42
  • @dmcr_code Yes, the pointer is constant and can't be changed. – nouney Mar 31 '14 at 10:43
  • 1) Then it might not be acceptable in all cases when someone wants to change it to smth else (that's why I said, in that case programmer should just ensure that between `malloc` and `free` no "bad" memory gets assigned to the pointer) 2) Also the reason I said to initialize pointers to NULL always - is for cases, when one doesn't want to use `malloc` straight away; so just to develop good habit of initializing to NULL –  Mar 31 '14 at 10:47
  • A `const` pointer is just a roundabout way of creating what is essentially a regular variable. It takes away the *principal reason* for using pointers in the first place. – vonbrand Mar 31 '14 at 11:13
0

The only answer is discipline. Make sure each malloc(3) has its corresponding free(3). That means defining some policy (where are such variables created and initialized, where are they destroyed) and following it rigurously. Define the part of the program responsible for managing each variable.

There are tools that help detect problems (i.e., valgrind), but fixing the mess afterwards is hard.

vonbrand
  • 11,412
  • 8
  • 32
  • 52