Main Content

CERT C: Rule MEM30-C

Do not access freed memory

Description

Rule Definition

Do not access freed memory.1

Polyspace Implementation

This checker checks for:

  • Accessing previously freed pointer

  • Freeing previously freed pointer

Examples

expand all

Issue

Accessing previously freed pointer occurs when you attempt to access a block of memory after freeing the block by using the free function.

Risk

When a pointer is allocated dynamic memory by using malloc, calloc or realloc, it points to a memory location on the heap. When you use the free function on this pointer, the associated block of memory is freed for reallocation and the pointer becomes a dangling pointer. Attempting to access this block of memory by dereferencing the dangling pointer can result in unpredictable behavior or a segmentation fault.

Fix

The fix depends on the root cause of the defect. Determine if you intended to free the memory later or allocate another memory block to the pointer before access.

As a best practice, after you free a memory block, assign the corresponding pointer to NULL. Before dereferencing pointers, check them for NULL values and handle the error. In this way, you are protected against accessing a freed block.

Example — Accessing Previously Freed Pointer Error
#include <stdlib.h>
#include <stdio.h>
 int increment_content_of_address(int base_val, int shift)
   { 
    int j;
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return 0;

    *pi = base_val;
    free(pi);

    j = *pi + shift; //Noncompliant
    /* Defect: Reading a freed pointer */
 
    return j;
   }

The free statement releases the block of memory that pi refers to. Therefore, dereferencing pi after the free statement is not valid.

Correction — Free Pointer After Last Use

One possible correction is to free the pointer pi only after the last instance where it is accessed.

#include <stdlib.h>

int increment_content_of_address(int base_val, int shift)
{
    int j;
    int* pi = (int*)malloc(sizeof(int));
    if (pi == NULL) return 0;

    *pi = base_val;

    j = *pi + shift;
    *pi = 0;

    /* Fix: The pointer is freed after its last use */
    free(pi);               
    return j;
}
Issue

Freeing previously freed pointer occurs when you attempt to free the memory allocated to a pointer after already freeing the pointer by using the free function.

Risk

Attempting to free the memory associated with a previously freed pointer might corrupt the memory management of the program and cause a memory leak. This defect might allow an attacker to access the memory and execute arbitrary code.

Fix

To avoid this defect, assign pointers to NULL after freeing them. Check the pointers for NULL value before attempting to access the memory associated with the pointer. In this way, you are protected against accessing a freed block.

Example — Freeing Previously Freed Pointer
#include <stdlib.h>
#include <stdio.h>
int getStatus();
void double_deallocation(void)
{
	int* pi = (int*)malloc(sizeof(int));
	if (pi == 0) return;

	*pi = 2;
	/*...*/
	if(getStatus()==1)
	{
		/*...*/
		free(pi);
	}
	free(pi); //Noncompliant //Noncompliant
}

The second free statement attempts to release the block of memory that pi refers to, but the pointer pi might already be freed in the if block of code. This second free statement might cause a memory leak and security vulnerabilities in the code. Polyspace® flags the second free statement.

Correction — Check Pointers Before Calling free

One possible correction is to assign freed pointers to NULL and to check pointers for NULL before freeing them.

#include <stdlib.h>
#include <stdio.h>
int getStatus();
void double_deallocation(void)
{
	int* pi = (int*)malloc(sizeof(int));
	if (pi == 0) return;

	*pi = 2;
	/*...*/
	if(getStatus()==1)
	{
		/*...*/
		if(pi!=NULL)
		{
			free(pi);
			pi= NULL;
		}
	}
	/*...*/
	if(pi!=NULL)
	{
		free(pi);
		pi= NULL;
	} //Compliant
}

In this case, the memory allocated to pointer pi is freed only if it is not already freed.

Example – Freeing Pointer Previously Reallocated With Possibly Zero Size
#include <stdlib.h>
  
void reshape(char *buf, size_t size) {
  char *reshaped_buf = (char *)realloc(buf, size);
  if (reshaped_buf == NULL) {
    free(buf); //Noncompliant
  }
}

In this example, the argument size of the reshape() function can be zero and result in a zero-size reallocation with realloc(). In some implementations such as the GNU® library, zero-size reallocations free the memory leading to a double free defect.

Correction – Guard Against Zero-Size Reallocations

One possible correction is to check size argument of realloc() for zero values before use. If the size argument is zero, you can simply free the memory instead of reallocating it.

#include <stdlib.h>

void reshape(char *buf, size_t size) {
  if (size != 0) {
    char *reshaped_buf = (char *)realloc(buf, size);
    if (reshaped_buf == NULL) {
      free(buf);
    }
  }
  else {
    free(buf);
  }

}

Check Information

Group: Rule 08. Memory Management (MEM)

Version History

Introduced in R2019a

expand all


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.