CertC++-MEM34¶
Only free memory allocated dynamically
Required inputs: IR, StaticSemanticAnalysis
The C Standard, Annex J [ ISO/IEC 9899:2011], states that the behavior of a program is undefined when
The pointer argument to the
freeorreallocfunction does not match a pointer earlier returned by a memory management function, or the space has been deallocated by a call tofreeorrealloc.
See also undefined behavior 179.
Freeing memory that is not allocated dynamically can result 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. The
realloc() function is used to resize a block of dynamic memory. If
realloc() is supplied a pointer to memory not allocated by 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.
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum { MAX_ALLOCATION = 1000 };
int main(int argc, const char *argv[]) {
char *c_str = NULL;
size_t len;
if (argc == 2) {
len = strlen(argv[1]) + 1;
if (len > MAX_ALLOCATION) {
/* Handle error */
}
c_str = (char *)malloc(len);
if (c_str == NULL) {
/* Handle error */
}
strcpy(c_str, argv[1]);
} else {
c_str = "usage: $>a.exe [string]";
printf("%s\n", c_str);
}
free(c_str);
return 0;
}
Compliant Solution
This compliant solution eliminates the possibility of
c_str referencing memory that is not allocated dynamically
when passed to
free():
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
enum { MAX_ALLOCATION = 1000 };
int main(int argc, const char *argv[]) {
char *c_str = NULL;
size_t len;
if (argc == 2) {
len = strlen(argv[1]) + 1;
if (len > MAX_ALLOCATION) {
/* Handle error */
}
c_str = (char *)malloc(len);
if (c_str == NULL) {
/* Handle error */
}
strcpy(c_str, argv[1]);
} else {
printf("%s\n", "usage: $>a.exe [string]");
return EXIT_FAILURE;
}
free(c_str);
return 0;
}
Noncompliant Code Example (
realloc())
In this noncompliant example, the pointer parameter to
realloc(),
buf, does not refer to dynamically allocated memory:
#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:
#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
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 |
Related Guidelines
| Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| CERT C Secure Coding Standard | MEM31-C. Free dynamically allocated memory when no longer needed | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CERT C | MEM51-CPP. Properly deallocate dynamically allocated resources | Prior to 2018-01-12: CERT: Unspecified Relationship |
| ISO/IEC TS 17961 | Reallocating or freeing memory that was not dynamically allocated [xfree] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CWE 2.11 | CWE-590, Free of Memory Not on the Heap | 2017-07-10: CERT: Exact |
Bibliography
| [ ISO/IEC 9899:2011] | Subclause J.2, "Undefined Behavior" |
| [ Seacord 2013b] | Chapter 4, "Dynamic Memory Management" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
possible_stack_free |
{name0} possibly released by call to {node0} is a stack or static object |
None |
False |
stack_free |
{name0} released by call to {node0} is a stack or static object |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
resources¶
resources
Deallocator calls of these resources are checked for being called with a stack/static object; the names are a selection of rules in the Resources group.Type: set[str]
Default:
{'C++ArrayHeapMemory', 'C++HeapMemory', 'CudaAsyncMemory', 'CudaDeviceMemory', 'CudaDriverAsyncMemory', 'CudaHostMemory', 'CudaManagedMemory', 'HeapMemory', 'UniquePtrHeapMemory'}
witness_paths¶
witness_paths : bool = True