Effective Prevention of Memory Leaks in Embedded C Programming

Click the blue “One Bite Linux” in the upper left corner and select “Set as Favorite

Get the latest articles immediately

☞【Resource】Learning Path for Embedded Driver Engineers
☞【Resource】Linux Embedded Knowledge Points - Mind Map - Free Access
☞【Employment】A Comprehensive IoT Project Based on Linux for Your Resume
☞【Employment】Resume Template for Job Hunting

1. Introduction

Recently, our department has encountered multiple issues related to memory leaks across different products, specifically manifested as the single board resetting after running for several months due to memory exhaustion.

On one hand, memory leak issues are considered basic errors; such problems, if overlooked in production, can have severe consequences. On the other hand, since memory leaks can lead to the single board resetting after a fixed runtime, the only way to resolve them is through bulk upgrades, which can have a significantly adverse impact.

Moreover, the recurrence of such issues, especially one instance caused by modifications made by our senior employees, indicates that many of our staff still do not have a profound understanding of memory leak issues.

This article aims to introduce the principles and inspection methods related to memory leaks, with the hope of preventing such issues from occurring during the coding review phase.

Note: There are various methods to prevent memory leak issues, such as enhancing code reviews, tool detection, and memory testing. This article focuses on improving the capabilities of developers.

Effective Prevention of Memory Leaks in Embedded C Programming

2. Principles of Memory Leak Issues

2.1 Storage Method of Heap Memory in C Code

Memory leak issues only occur when using heap memory, as stack memory does not have memory leak problems due to its automatic allocation and deallocation. The function used to allocate heap memory in C code is malloc, and a common memory allocation code is as follows:

char *info = NULL;    /**Converted string**/
info = (char*)malloc(NB_MEM_SPD_INFO_MAX_SIZE);
if( NULL == info)
{
    (void)tdm_error("malloc error!\n");
    return NB_SA_ERR_HPI_OUT_OF_MEMORY;
}

Since the malloc function actually returns a memory address, the variable storing heap memory must be a pointer (unless the code is written extremely poorly). To reiterate, the variable storing heap memory must be a pointer, which is crucial for understanding the main theme of this article. Of course, this pointer can be a single pointer or a multiple pointer.

The malloc function has many variants or wrappers, such as g_malloc, g_malloc0, and VOS_Malloc. These functions ultimately call the malloc function.

2.2 Methods of Obtaining Heap Memory

Upon seeing the title of this section, some may wonder, isn’t the malloc function mentioned in the previous section a method for obtaining heap memory? Indeed, using the malloc function is the most direct method of acquisition, but knowing only this method can lead to pitfalls. Generally speaking, there are two methods of obtaining heap memory:

Method 1: Directly assigning the function’s return value to a pointer, typically represented as follows:

char *local_pointer_xx = NULL;
local_pointer_xx = (char*)function_xx(para_xx, …);

Functions that involve memory allocation generally return pointer types, for example:

GSList* g_slist_append (GSList   *list, gpointer  data);

Method 2: Using the pointer address as a function return parameter to store the heap memory address, typically represented as follows:

int ret;
char *local_pointer_xx = NULL;    /**Converted string**/
ret = (char*)function_xx(..., &local_pointer_xx, ...);

Functions that involve memory allocation typically have a double pointer as one of the parameters, for example:

__STDIO_INLINE _IO_ssize_t;
getline (char **__lineptr, size_t *__n, FILE *__stream);

Using malloc to allocate memory is a specific representation of Method 1. In fact, these two methods are fundamentally the same; both involve indirect memory allocation within the function, differing only in how the memory is passed. Method 1 passes the memory pointer through the return value, while Method 2 passes the memory pointer through parameters.

2.3 Three Elements of Memory Leaks

The most common memory leak issues consist of the following three elements:

Element 1: There is a local pointer variable defined within the function;

Element 2: The local pointer has obtained memory through one of the two heap memory acquisition methods mentioned earlier;

Element 3: The memory is not released before the function returns (including both normal and abnormal branches) and is not saved to other global variables or returned to the upper-level function.

2.4 Misconceptions About Memory Release

Anyone who has used C to write code should know that heap memory needs to be released after allocation. But why do memory leak issues still occur so easily? On one hand, it is due to developers’ lack of experience, awareness, or momentary negligence; on the other hand, it is due to misconceptions about memory release. Many developers believe that the memory that needs to be released should be limited to the following two types:

1) Memory allocated directly using memory allocation functions like malloc, g_malloc, etc.;

2) Interfaces familiar to the developer where memory allocation occurs, such as iBMC colleagues should know that calling the following interface requires releasing the memory pointed to by list:

dfl_get_object_list(const char* class_name, GSList **list);

Following this line of thinking while writing code, when encountering unfamiliar interfaces that require memory release, the awareness of needing to release memory is completely absent, leading to natural occurrences of memory leak issues.

3. Methods for Inspecting Memory Leak Issues

Inspecting memory leak issues fundamentally requires cultivating good coding inspection habits. Corresponding to the three elements of memory leaks, the following three points should be achieved:

1) When seeing local pointers in a function, be alert to memory leak issues and develop a habit of further investigation.

2) Analyze the assignment operations of local pointers to determine whether they belong to one of the two heap memory acquisition methods mentioned earlier. If they do, analyze what the returned pointer actually points to: is it global data, static data, or heap memory? For unfamiliar interfaces, find the corresponding documentation or source code for analysis; alternatively, check other parts of the code for references to this interface to see if memory has been released.

3) If it is confirmed that there are memory allocation operations for local pointers, analyze the destination of that memory. Will it be saved in a global variable? Or will it be returned as a function return value? If neither, check all the places with “return” in the function to ensure memory is correctly released.

Original article: https://my.oschina.net/u/4526289/blog/4539592

end

One Bite Linux

Follow, reply 【1024】 to receive a wealth of Linux materials

Collection of Exciting Articles

Article Recommendations

【Collection】ARM
【Collection】Fan Q&A
【Collection】All Originals
CollectionLinuxIntroduction
CollectionComputer Networks
CollectionLinux Drivers
【Resource】Learning Path for Embedded Driver Engineers
【Resource】All Knowledge Points of Linux Embedded – Mind Map

Leave a Comment