Memory Leaks: 7 Q&As

Last Updated : 31 July, 2022 · 3 min read

articles banner image

Garbage collection is implemented in the majority of high-level programming languages. In C programming language, there are no signs of automatic garbage collection. Thus, programmers of this low-level language are responsible for the memory management that occurs within a program. Memory leaks are, in a way, a consequence of poor memory management.

Take a look at the 7 Q&As below to understand this and more.

7 Q&As about Memory Leaks

1. What is a memory leak?

A memory leak is a block of dynamically allocated memory that is not freed and that has lost all the references to it. In C programming language this occurs, when heap memory is dynamically allocated with functions, like malloc or calloc but not freed (with the function free) when this memory is no longer needed. Or when dynamically allocated memory is made inaccessible before it is freed, even though, it is still needed.

2. What types of programming mistakes lead to memory leaks?

There are three common mistakes that lead to memory leaks:

[1] Improper handing of a return value.

Example 1: A memory leak because of an unhandled return value.

# include <stdio.h>
# include <stdlib.h>
char *get_ptr ()
{
    
char *ptr = ( char *)malloc(10);
    
return ptr;
}
					
int main ()
{
    
get_ptr (); //pointer to heap memory is lost
    
return 0;
}
					

In the example above (Example 1), a memory leak occurs because a pointer is lost that contains the address to the dynamically allocated memory block. To fix this memory leak, we need to handle the return value of the function get_ptr and free it when the memory is no longer necessary. Just like it is done in the example below (Example 2).

Example 2: Proper memory management of the returned value.

# include <stdio.h>
# include <stdlib.h>
char *get_ptr ()
{
    
char *ptr = ( char *)malloc(10);
    
return ptr;
}
					
int main ()
{
    
char *ptr = get_ptr ();
    
// ...
    
free (ptr);
    
return 0;
}
					

Note: make sure to free dynamically allocated memory after you no longer need it.

[2] Another common memory management mistake is improper freeing of an array of pointers.

Example 3: A memory leak because of improper freeing of an array of pointers.

    
# include <stdio.h>
    
# include <stdlib.h>
    
int main ()
    
{
        
char **ptr_2D = ( char **)calloc(2, sizeof( char *));
        
*ptr_2D = ( char *)calloc(5, sizeof( char ));
        
free (ptr_2D); //array of pointers
        
free (*ptr_2D); //this pointer cannot be accessed anymore
        
return 0;
    
}

Here (Example 3), a memory leak is caused by the freeing of the ptr_2D array (on line 7) because it contains elements that are not freed at that point. In this way, dynamically allocated memory (on line 6) is no longer accessible by the program. To fix this memory leak, we need to free the element within the ptr_2D array first. Just like you can see below (example 4).

Example 4: Freeing an array with a dynamically allocated pointer in C.

    
# include <stdio.h>
    
# include <stdlib.h>
    
int main ()
    
{
        
char **ptr_2D = ( char **)calloc(2, sizeof( char *));
        
*ptr_2D = ( char *)calloc(5, sizeof( char ));
        
free (*ptr_2D); //freeing elements within the array first
        
free (ptr_2D); //now the array of pointers can be freed without memory leaks
        
return 0;
    
}

[3] One more common mistake that leads to memory leaks is reassignment. When we reassign a pointer that holds an address to an allocated memory, we can get a memory leak in C programming language.

Example 5: A memory leak because of reassignment.

# include <stdio.h>
# include <stdlib.h>
int main ()
{
    
int *ptr = ( int *)calloc(5, sizeof( int ));
    
ptr = NULL;
    
free (ptr); // memory allocated on line 5 is not accessible anymore
    
return 0;
}
					

In the example above (Example 5), a pointer ptr is pointed to NULL (on line 6). This causes a memory leak because the allocated memory (on line 5) cannot be freed anymore. To fix this memory leak, we need to free (example 6) or set another pointer to (example 7) the allocated memory before assigning the pointer ptr to NULL.

Example 6: Freeing before reassignment.

# include <stdio.h>
# include <stdlib.h>
int main ()
{
    
int *ptr = ( int *)calloc(5, sizeof( int ));
    
free (ptr);
    
ptr = NULL;
    
return 0;
}
					

Example 7: Setting another pointer to the allocated memory address before reassignment.

# include <stdio.h>
# include <stdlib.h>
int main ()
{
    
int *ptr = ( int *)calloc(5, sizeof( int ));
    
int *another_ptr = ptr;
    
ptr = NULL;
    
// ...
    
free (another_ptr);
    
return 0;
}
				

Note: it is safe to free a NULL pointer.

3. Do memory leaks occur on the stack in C?

No. Memory leaks do not occur on the stack in C because stack objects have automatic storage duration. Whenever an object leaves its scope, it is automatically freed.

Memory leaks only occur because of the improper handling of those objects that have dynamic storage duration. In other words, memory leaks can only occur with heap objects.

4. How to prevent memory leaks in C?

For one, it is a great idea to avoid the most common memory management mistakes discussed in the answer 2. For two, it helps to follow the golden rule, which states that for each and every malloc and calloc call, you should call free.

This applies to every path of execution. This means that if an error occurs, dynamically allocated memory should still be freed. Just like it is freed in the example below (consider line 13).

Example 8: Freeing on every path of execution (free on line 13 prevents a memory leak in case of error).

# include <stdio.h>
# include <stdlib.h>
void take_action ()
{
    
int *ptr = ( int *)malloc(sizeof( int ) * 5);
    
if (ptr == NULL)
    
{
        
return ;
    
}
    
int *ptr_2 = ( int *)malloc(sizeof( int ) * 5);
    
if (ptr == NULL)
    
{
        
free (ptr); //without a free call here, error above would cause a memory leak
        
return ;
    
}
    
// ...
    
free (ptr);
    
free (ptr_2);
}
					
int main ()
{
    
take_action ();
    
return 0;
}
					

5. In what types of applications are memory leaks especially dangerous?

Memory leaks are never desirable, to say the least. However, they are way more dangerous and detrimental to long-running application. Such applications, among others, include (1) servers, (2) browsers and (3) graphic editors.

In these and other long-running applications memory leaks have a higher probability to result in crashes, given that the number of leaks continuously grow over time.

6. How to find memory leaks in C?

In order to find memory leaks, you may reserve to, at least, two options. One is to use runtime detection tools like Valgrind or Dr. Memory. Two, implement a pair of counters of allocated and deallocated memory or of malloc and free function calls.

Example 9: Counters for free and malloc calls

    
static unsigned int Allocated = 0;
    
static unsigned int Deallocated = 0;
    
void *Allocate_memory ( size_t size)
    
{
        
void *ptr = NULL;
        
ptr = malloc (size);
        
if (NULL != ptr)
        
{
            
++Allocated;
        
}
        
else
        
{
            
//Log error
        
}
        
return (ptr);
    
}
    
void Deallocate_memory ( void *ptr)
    
{
        
if (ptr != NULL)
        
{
            
free (ptr);
            
++Deallocated;
        
}
    
}
    
int Is_all_memory_freed ()
    
{
        
return Allocated == Deallocated;
    
}

Using the counter functions (example 9) helps you to keep track of all the allocations and deallocations within your program. The Is_all_memory_freed function informs you, if all the allocated memory is freed.

Note: counter functions add overhead to a C program.

7. Do memory leaks pose security risks?

Yes. Memory leaks pose security risks to publicly accessible applications. If a malicious user can cause a memory leak by a certain sequence of actions in a publicly accessible application (think of a web-browser or a router), then such an application can be negatively affected by the malicious users.

Summary

To sum it all up, memory leaks are lost references to memory addresses that are not freed. These lost references, in turn, downgrade your software and make it more prone to crashes and vulnerable to malicious attacks.

To improve the quality of your programs, prevent memory leaks by following the best practices and utilize a tracking option for memory leaks. So that your application can be memory leaks free.