Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

As noted in under undefined behavior 179 of in Annex J of the C Standard [ISO/IEC 9899:2011], the behavior of a program is undefined when

...

Code Block
bgColor#FFCCCC
langc
#include <stdlib.h>
 
int f(size_t n) {
  int error_condition = 0;

  int *x = (int *)malloc(n * sizeof(int));
  if (x == NULL)
    return -1;

  /* Use x and set error_condition on error. */

  if (error_condition == 1) {
    /* Handle error */
    free(x);
  }

  free(x);
  return error_condition;
}

...

In this compliant solution, the memory referenced by x is freed only freed once. This is accomplished by eliminating the call to free() when error_condition is set:

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
 
int f(size_t n) {
  int error_condition = 0;

  if (n > SIZE_MAX / sizeof(int)) {
    return -1;
  }

  int *x = (int*)malloc(n * sizeof(int));
  if (x == NULL) {
    /* Report allocation failure to caller. */
    return -1;
  }

  /* Use x and set error_condition on error. */

  if (error_condition != 0) {
    /* Handle error condition and proceed. */
  }

  free(x);

  x = 0;
  return error_condition;
}

Note that this solution checks for numeric overflow . (See see INT32-C. Ensure that operations on signed integers do not result in overflow). It also complies with MEM01-C. Store a new value in pointers immediately after free().

Noncompliant Code Example (realloc())

...

Code Block
bgColor#FFCCCC
langc
#include <stdlib.h>
 
/* p is a pointer to dynamically allocated memory. */
void func(void *p, size_t size) {
  p2 = realloc(p, size);
  if (p2 == NULL) {
    /* p may be indeterminate when (size == 0). */ 
    free(p); 
    return;
  }
}

Subclause 7.22.3 of the C Standard [ISO/IEC 9899:2011] states:

...

If realloc() is called with size equal to 0 , and then if a null pointer is returned, the old value should be unchanged. However, there are some common but nonconforming implementations that free the pointer, including the following:

...

In this compliant solution, allocations of zero 0 bytes are prevented, ensuring that p is freed exactly once:

Code Block
bgColor#ccccff
langc
#include <stdlib.h>
 
/* p is a pointer to dynamically allocated memory. */
void func(void *p, size_t size) {
  if (size) {
    p2 = realloc(p, size);
    if (p2 == NULL) {
      free(p);
      return;
    }
  } else {
    free(p);
    return;
  }
}

...

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

MEM31-C

highHigh

probableProbable

mediumMedium

P12

L1

Automated Detection

Tool

Version

Checker

Description

Compass/ROSE

Coverity

Include Page
Coverity_V
Coverity_V

RESOURCE_LEAK

USE_AFTER_FREE

Finds resource leaks from variables that go out of scope while owning a resource

Can find the instances where a freed memory is freed again. Coverity Prevent cannot discover all violations of this rule, so further verification is necessary

Fortify SCA

5.0

Double Free

 

Klocwork

Include Page
Klocwork_V
Klocwork_V

MLK
UFM.FFM

 

LDRA tool suite

Include Page
LDRA_V
LDRA_V

484 S

Fully implemented

Splint

Include Page
Splint_V
Splint_V
  

...

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

Related Guidelines

Bibliography

[ISO/IEC 9899:2011]Subclause 7.22.3, "Memory Management Functions"
Annex J, J.2, "Undefined behaviorBehavior"
[MIT 2005] 
[OWASP Double Free]"Double Free"
[Viega 2005]"Doubly Freeing Memory"
[VU#623332] 

...