QC 8: Memory Allocation & Deallocation

In any system, memory buffers are allocated and de-allocated. However, the former happens regularly, but the latter gets missed out leading to memory leaks, corruptions, crashes and more similar disasters. There are enough tools around to catch these leaks and can be employed to detect the same. Rational Purify, Valgrind are some names that come up quite often and are used extensively across the globe.

However, as a pride-filled-programmer one would like to ensure that any programs or modules written by them don’t suffer from these trivial issues. This requires that every buffer/pointer allocated is meticulously tracked and accounted for i.e. each allocated pointer is tracked and ensured that is freed at the end of the program. Hence, a few habits/programming practices are described below which describe some simple and effective programming practices that can implemented in day-t0-day development with highly effective results.

Habit 1: For every *malloc*, write a *free*

Whenever a module is being implemented, one should make a habit of coupling *malloc* with a corresponding *free*. Consider a simple test program being written to validate an underlying algorithm. In this test program, we need to allocate 3 buffers to pass to the algorithm, which are allocated using the malloc method. It is a very good practice to implement their corresponding free immediately and insert all the requisite code in between.

.............
pPtr1 = malloc();
pPtr2 = malloc();
pPtr3 = malloc();
............
....
invoke_algorithm(pPtr1, pPtr2, pPtr3);
....
............
free(pPtr3);
free(pPtr2);
free(pPtr1);

This is a simple program where the pointer is allocated, used and de-allocated at the same software abstraction layer. However, typically embedded or software applications are not this simple or straight-forward.

Habit 2: Never Free a pointer that you *don’t* own

In a multi-layered hierarchical software, pointers are allocated at one place and pass downstream to other modules. The beauty of pointers is that their content, context, intent and scope is available to every function that receives them. Hence, when a pointer is no longer useful, it can easily be *de-allocated* or *freed* from any point. An example illustration is shown below in terms of 2 functions func1 and func2 where func1 allocates a pointer and passes it to func2 which frees the same.

void func1()
{
      // Variables
      int    *pPtr1;
      // Allocate Memory for pPtr1;
      pPtr1 = (int *) malloc(sizeof(int));
      .........................
      ........
      func2(pPtr1);
      ........
      .........................
      // De-allocate the memory buffer
      free(pPtr1);
}

void func2(int *pInpPtr)
{
      .....................
      ........
      // Uses the pointer pInpPtr
      ........
      .....................
      // Frees the pointer - CREATION OF BUG !!!
      free(pInpPtr);
}

In this example, func1 assumes that func2 hasn’t modified the pointer and goes ahead and tries to free up the same. However, as the pointer is already freed, a crash is the least one can expect in this scenario. Good programming practices advocate that all pointers are allocated and correspondingly freed at the same software abstraction level. In case of an algorithm or module, it would be best if all pointers are handled at one level. However, the least one can do is that allocate and free pointers at the same software abstraction level. In short, allocate and free pointers at the same software abstraction level.

Implementing the advocated principle, the example would be rewritten as below

void func1()
{
      // Variables
      int    *pPtr1;
      // Allocate Memory for pPtr1;
      pPtr1 = (int *) malloc(sizeof(int));
      .........................
      ........
      func2(pPtr1);
      ........
      .........................
      // De-allocate the memory buffer
      free(pPtr1);
}

void func2(int *pInpPtr)
{
      .....................
      ........
      // Uses the pointer pInpPtr
      ........
      .....................
}

Habit 3: Beware of pointer copies

Pointers provide a lot of flexibility in terms of context and information traversal. Pointers can be copied and be used in the same vein as the originally allocated ones.  System doesn’t associate a specific variable to a pointer entity i.e. pointer is a memory address and any number of variables i.e. pointer variables can be pointing to the same address. When multiple copies are made, care should be exercised to ensure that spurious free are avoided.

Consider the example below where func1 passes a pointer to func2, which makes a copy of the same and then frees the same. This has the same effect as the one described in Habit 2 above.

void func1()
{
      // Variables
      int    *pPtr1;
      // Allocate Memory for pPtr1;
      pPtr1 = (int *) malloc(sizeof(int));
      .........................
      ........
      func2(pPtr1);
      ........
      .........................
      // De-allocate the memory buffer
      free(pPtr1);
}

void func2(int *pInpPtr)
{
      int    *pLocalPtr = pInpPtr;
      .....................
      ........
      // Uses the pointer pLocalPtr
      ........
      .................
      // Frees the pointer
      // Though the original pointer is not employed,
      // the effect is same - CREATION OF BUG !!!
      free(pLocalPtr);
}

Pointers are extremely powerful, but require a lot of care and caution while being effectively employed.

Habit 4: Never forget to initialize a freed pointer to NULL

Last but definitely not the least, once a pointer has been freed, the variable should be set to NULL. This is to avoid spurious accesses or free. This is a stylistic statement and a recommended practice. Neither the program’s performance improves nor does it decrease. However, it does help to improve the quality of software being developed drastically.

In general, pointers are like Super-Powers quoted in Spider-Man movie – “With greater powers come greater responsibilities…” One needs to shoulder the same responsibly

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s