Freeing memory that is not allocated dynamically can lead to serious errors. The specific consequences of this error depends on the compiler, but ranges from nothing to abnormal program termination. Regardless of the compiler, avoid calling free()
on non-dynamic memory.
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 also terminate abnormally.
Non-compliant Code Example 1
In this example, a file is opened for reading. If the file is opened successfully, memory is allocated by malloc()
and referenced by str
. A message indicating that the file was opened properly is copied into the dynamically-allocated memory referenced by str
and printed. Afterwards, the memory is deallocted by calling free()}. If the file does not open correctly, however, {{str
is set to a string literal. Because str
now references memory that was not dynamically allocated, an error will occur when this memory is freed.
FILE *file = NULL; char *str = NULL, *fname="~/config_file"; size_t size = 100; file = fopen("~/config_file","r"); if (file != NULL) { str = (char *)malloc(size); snprintf(str, size, "File %s opened properly", fname); printf("LOG: %s\n", str); } else { str = "ERROR OPENING FILE"; printf("LOG: %s\n", str); } free(str);
Compliant Solution 1
In the compliant solution, the call to free()
has been moved inside the conditional statement to ensure that only dynamic memory is freed.
FILE *file = NULL; char *str = NULL, *fname="~/config_file"; size_t size = 100; file = fopen("~/config_file","r"); if (file != NULL) { str = (char *)malloc(size); snprintf(str, size, "File %s opened properly", fname); printf("LOG: %s\n", str); free(str); /* only dynamic memory is freed */ } else { str = "ERROR OPENING FILE"; printf("LOG: %s\n", str); }
Non-compliant Code Example 2
This example attempts to resize the string referenced by buf
to make enough room to append the 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.
void append(char *buf, size_t count, size_t size) { char *line = " <- THIS IS A LINE"; int line_len = strlen(line); if ((count + line_len) > size) { buf = realloc(buf,count+line_len); size = count + line_len; } strncat(buf,line,line_len); } int main(void) { append("AAAAA",5,6); return 0; }
Compliant Solution 2
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.
/* NOTE: buf must point to dynamically allocated memory */ void append(char *buf, size_t count, size_t size) { char *line = " <- THIS IS A LINE"; int line_len = strlen(line); if ((count + line_len) > size) { buf = realloc(buf,count+line_len); size = count + line_len; } strncat(buf,line,line_len); } int main(void) { size_t size = 6, count = 5; char *str = malloc(size); strncpy(str,"AAAAA", size); 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.
j1This violates recommendation 1 (sort of)