Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Updated references from C11->C23

The pointer argument to the free or realloc function does not match a pointer earlier returned by a memory management function, or the space has been deallocated by a call to free or realloc.

See also undefined behavior 179.

Freeing memory that is not allocated dynamically can cause a serious error. The specifics and extent of damage caused by this error depends on the compiler in use, but can range from nothing to unintended and unexpected program termination. Regardless of the implementation, calling free(...) on non-dynamic memory should be avoidedresult in heap corruption and other serious errors. Do not call free() on a pointer other than one returned by a standard memory allocation function, such as malloc(), calloc(), realloc(), or aligned_alloc().

A similar situation arises when realloc() is supplied a pointer to non-dynamically allocated memory. According to C99:

The realloc function de-allocates the old object pointed to by ptr and returns a pointer to a new object that has the size specified by size. The contents of the new object shall be the same as that of the old object prior to de-allocation, up to the lesser of the new and old sizes.

Essentially, the realloc The realloc() function is used to resize a block of dynamic memory. If realloc() is supplied a pointer to memory not allocated by another dynamic allocation routine (malloc or calloc) a series error could occur.

Non-compliant Code Example 1

In this example, a file is opened for reading. If the file is opened successfully, then a block of memory is allocated on the heap with malloc and pointed to by str. A message indicating that the file was opened properly is copied into a block of dynamic memory pointed to by str, and the message is printed via the log_it function.  After log_it is called, the dynamic memory is freed. However, if the file does not open correctly, then str will be set to a non-dynamic string. When this str is freed, since it points to non-dynamic memory, an error will occur.

a standard memory allocation function, the behavior is undefined. One consequence is that the program may terminate abnormally.

This rule does not apply to null pointers. The C Standard guarantees that if free() is passed a null pointer, no action occurs.

Noncompliant Code Example

This noncompliant code example sets c_str to reference either dynamically allocated memory or a statically allocated string literal depending on the value of argc. In either case, c_str is passed as an argument to free(). If anything other than dynamically allocated memory is referenced by c_str, the call to free(c_str) is erroneous.

Code Block
bgColor#FFcccc
langc
#include <stdlib.h>
#include <string
Code Block

#include <stdlib.h>
#include <stdio.h>
 
void log_it(char *msg_buf) {
  printf("LOG: %s\n", msg_buf);
}

enum { MAX_ALLOCATION = 1000 };

int main(void) {

  FILE *file = NULL;int argc, const char *argv[]) {
  char *c_str  = NULL, *fname="~/config_file";
  size_t size len;

  if (argc = 100;

= 2) {
    filelen = fopen("~/config_file","r")strlen(argv[1]) + 1;
    if (filelen != NULL> MAX_ALLOCATION) {
      /* Handle error */
    }
    c_str = (char *)malloc(sizelen);
    if (c_str == NULL) {
    snprintf(str,size,"File %s opened properly",fname);  /* Handle error */
    }
    logstrcpy(c_it(strstr, argv[1]);
  }
  else {
    c_str = "FILE OPENEDusage: $>a.exe [string]";
     log_it(printf("%s\n", c_str);
  }  
  free(c_str);
  return 0;
}	

Compliant

...

Solution

This compliant example is very similar to the non-compliant example above. The only modification is the call to free has been moved inside the conditional statement to ensure that only dynamic memory is freed.  solution eliminates the possibility of c_str referencing memory that is not allocated dynamically when passed to free():

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
#include <string
Code Block

#include <stdlib.h>
#include <stdio.h>
 
void log_it(char *msg_buf) {
  printf("LOG: %s\n", msg_buf);
}enum { MAX_ALLOCATION = 1000 };

int main(void) {

  FILE *file = NULL;int argc, const char *argv[]) {
  char *c_str  = NULL, *fname="~/config_file";
  size_t size = 100len;

  file = fopen("~/config_file","r");
  if (fileargc !== NULL2) {
    strlen = (char *)malloc(size);    
    snprintf(str,size,"File %s opened properly",fname);
    log_it(str);
    free(str);strlen(argv[1]) + 1;
    if (len > MAX_ALLOCATION) {
      /* only dynamic memory is freed Handle error */	
  }
  else {}
    c_str = "FILE OPENED";
    log_it(str(char *)malloc(len);
  }  
  return 0;
}	

Non-compliant Code Example 2

This example attempts to resize the string referenced by buf to make enough room in buf to append another string, line. However, once in the function append, there is no way to determine how buf was allocated. When realloc is called on buf, since buf does not point to dynamic memory, an error may occur.  

Code Block

void append(char *buf, size_t count, size_t size  if (c_str == NULL) {
  char  *line = "/* <-Handle THISerror IS*/
 A LINE";  }
  int  line_len = strlen(linestrcpy(c_str, argv[1]);
  
}  if ((count + line_len) > size) else {
    buf = realloc(buf,count+line_lenprintf("%s\n", "usage: $>a.exe [string]");
    size = count + line_lenreturn EXIT_FAILURE;
  }
  strncat(buf,line,line_len);
}

int main(void) {
  append("AAAAA",5,6)free(c_str);
  return 0;
}

...

Noncompliant Code Example

...

(realloc())

In this noncompliant example, the pointer parameter to realloc(), buf, does not refer Correcting the above example is an exercise in documentation. Since realloc is used to resize the memory pointed to by buf, the function append has the precondition that buf must point to dynamically allocated memory.:

Code Block
bgColor#FFcccc
langc

/* NOTE: buf must point to dynamically allocated memory */

void append(char *buf, size_t count, size_t size) {#include <stdlib.h>
 
enum { BUFSIZE = 256 };
 
void f(void) {
  char buf[BUFSIZE];
  char *linep = " <- THIS IS A LINE";  (char *)realloc(buf, 2 * BUFSIZE);
  int line_lenif (p == strlen(lineNULL);
  {
  if ((count + line_len) > size) {
    buf = realloc(buf,count+line_len);
    size = count + line_len;
  }
  strncat(buf,line,line_len);
}	

int main(/* Handle error */
  }
}

Compliant Solution (realloc())

In this compliant solution, buf refers to dynamically allocated memory:

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
 
enum { BUFSIZE = 256 };
 
void f(void) {
  size_t sizechar *buf = 6, count = 5(char *)malloc(BUFSIZE * sizeof(char));
  char *strp = malloc(size);
  strncpy(str,"AAAAA", sizechar *)realloc(buf, 2 * BUFSIZE);
  if append(str,size,count);
  free(str); 
  return 0;
}

Compliant Code Example 2A

Alternatively, the function append could be rewritten not to use realloc(...) to resize buf. This solution goes beyond the scope of this document, but is nonetheless viable and, depending on the context of the program, may be preferred.

(p == NULL) {
    /* Handle error */
  }
}

Note that realloc() will behave properly even if malloc() failed, because when given a null pointer, realloc() behaves like a call to malloc().

Risk Assessment

The consequences of this error depend on the implementation, but they range from nothing to arbitrary code execution if that memory is reused by malloc()

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MEM34-C

High

Likely

Medium

P18

L1

Automated Detection

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V

invalid-free

Fully checked
Axivion Bauhaus Suite

Include Page
Axivion Bauhaus Suite_V
Axivion Bauhaus Suite_V

CertC-MEM34Can detect memory deallocations for stack objects
Clang
Include Page
Clang_V
Clang_V
clang-analyzer-unix.MallocChecked by clang-tidy; can detect some instances of this rule, but does not detect all
CodeSonar
Include Page
CodeSonar_V
CodeSonar_V

ALLOC.TM

Type Mismatch

Compass/ROSE

Can detect some violations of this rule

Coverity

Include Page
Coverity_V
Coverity_V

BAD_FREE

Identifies calls to free() where the argument is a pointer to a function or an array. It also detects the cases where
free() is used on an address-of expression, which can never be heap allocated. Coverity Prevent cannot discover all
violations of this rule, so further verification is necessary

Cppcheck

Include Page
Cppcheck_V
Cppcheck_V

autovarInvalidDeallocation
mismatchAllocDealloc
Partially implemented
Cppcheck Premium

Include Page
Cppcheck Premium_V
Cppcheck Premium_V

autovarInvalidDeallocation
mismatchAllocDealloc
Partially implemented
Helix QAC

Include Page
Helix QAC_V
Helix QAC_V

DF2721, DF2722, DF2723


Klocwork
Include Page
Klocwork_V
Klocwork_V
FNH.MIGHT
FNH.MUST

LDRA tool suite
Include Page
LDRA_V
LDRA_V

407 S, 483 S, 644 S, 645 S, 125 D

Partially implemented
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-MEM34-a

Do not free resources using invalid pointers
Parasoft Insure++

Runtime analysis
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

424, 673

Fully supported

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rule MEM34-C


Checks for:

  • Invalid free of pointer
  • Invalid reallocation of pointer

Rule fully covered.

PVS-Studio

Include Page
PVS-Studio_V
PVS-Studio_V

V585, V726
RuleChecker
Include Page
RuleChecker_V
RuleChecker_V
invalid-free
Partially checked
TrustInSoft Analyzer

Include Page
TrustInSoft Analyzer_V
TrustInSoft Analyzer_V

unclassified ("free expects a free-able address")

Exhaustively verified (see one compliant and one non-compliant example).

Related Vulnerabilities

CVE-2015-0240 describes a vulnerability in which an uninitialized pointer is passed to TALLOC_FREE(), which is a Samba-specific memory deallocation macro that wraps the talloc_free() function. The implementation of  talloc_free() would access the uninitialized pointer, resulting in a remote exploit.

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Key here (explains table format and definitions)

Taxonomy

Taxonomy item

Relationship

CERT C Secure Coding StandardMEM31-C. Free dynamically allocated memory when no longer neededPrior to 2018-01-12: CERT: Unspecified Relationship
CERT CMEM51-CPP. Properly deallocate dynamically allocated resourcesPrior to 2018-01-12: CERT: Unspecified Relationship
ISO/IEC TS 17961Reallocating or freeing memory that was not dynamically allocated [xfree]Prior to 2018-01-12: CERT: Unspecified Relationship
CWE 2.11CWE-590, Free of Memory Not on the Heap2017-07-10: CERT: Exact

Bibliography

[ISO/IEC 9899:2024]Subclause J.2, "Undefined Behavior"
[Seacord 2013b]Chapter 4, "Dynamic Memory Management"


...

Image Added Image Added Image Addedj1This violates recommendation 1 (sort of)