As noted under undefined behavior 179 in Annex J of the C Standard [ISO/IEC 9899:2011], the behavior of a program is undefined when
the pointer argument to the
free
orrealloc
function does not match a pointer earlier returned by a memory management function, or the space has been deallocated by a call tofree
orrealloc
.
Freeing memory that is not allocated dynamically can lead to serious errors similar to those discussed in MEM31-C. Free dynamically allocated memory when no longer needed. The consequences of this error depend on the implementation, but they range from nothing to abnormal program termination. Regardless of the implementation, do not call free()
on anything other than a pointer returned by a dynamic 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. The realloc()
function is used to resize a block of dynamic memory. If realloc()
is supplied a pointer to memory not allocated by a memory allocation function, such as malloc()
, the program may terminate abnormally.
This rule does not apply to null pointers. The standard officially declares that when given a null pointer, free()
does nothing.
Noncompliant Code Example
This noncompliant code example sets str
to reference either dynamically allocated memory or a statically allocated string literal depending on the value of argc
. In either case, str
is passed as an argument to free()
. If anything other than dynamically allocated memory is referenced by str
, the call to free(str)
is erroneous.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <string.h> enum { MAX_ALLOCATION = 1000 }; int main(int argc, const char *argv[]) { char *str = NULL; size_t len; if (argc == 2) { len = strlen(argv[1]) + 1; if (len > MAX_ALLOCATION) { /* Handle error */ } str = (char *)malloc(len); if (str == NULL) { /* Handle error */ } strcpy(str, argv[1]); } else { str = "usage: $>a.exe [string]"; printf("%s\n", str); } free(str); return 0; } |
Compliant Solution
This compliant solution eliminates the possibility of str
, referencing nondynamic memory when it is supplied to free()
:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> #include <string.h> enum { MAX_ALLOCATION = 1000 }; int main(int argc, const char *argv[]) { char *str = NULL; size_t len; if (argc == 2) { len = strlen(argv[1]) + 1; if (len > MAX_ALLOCATION) { /* Handle error */ } str = (char *)malloc(len); if (str == NULL) { /* Handle error */ } strcpy(str, argv[1]); } else { printf("%s\n", "usage: $>a.exe [string]"); return -1; } free(str); return 0; } |
Noncompliant Code Example (realloc()
)
In this noncompliant example, the pointer parameter to realloc()
, buf
, does not refer to dynamically allocated memory:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> enum { BUFSIZE = 256 }; void f(void) { char buf[BUFSIZE]; char *p = (char *)realloc(buf, 2 * BUFSIZE); if (p == NULL) { /* handle error */ } } |
Compliant Solution (realloc()
)
In this compliant solution, buf
refers to dynamically allocated memory:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <stdlib.h> enum { BUFSIZE = 256 }; void f(void) { char *buf = (char *)malloc(BUFSIZE * sizeof(char)); char *p = (char *)realloc(buf, 2 * BUFSIZE); if (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
Freeing or reallocating memory that was not dynamically allocated can lead 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 | ||||||
---|---|---|---|---|---|---|---|---|---|
Can detect some violations of this rule | |||||||||
| BAD_FREE | Identifies calls to | |||||||
| FNH.MIGHT | ||||||||
| 483 S | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
CERT C Secure Coding Standard | MEM31-C. Free dynamically allocated memory when no longer needed |
CERT C++ Secure Coding Standard | MEM34-CPP. Only free memory allocated dynamically |
ISO/IEC TS 17961 | Reallocating or freeing memory that was not dynamically allocatied [xfree] |
MITRE CWE | CWE-590, Free of invalid pointer not on the heap |
Bibliography
[Seacord 2013] | Chapter 4, "Dynamic Memory Management" |
[ISO/IEC 9899:2011] | Annex J, subclause J.2, "Undefined Behavior" |