Versions Compared

Key

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

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 avoided.

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) , such as malloc(), a series error could occur.

...

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.

Code Block
#include <stdlib.h>
#include <stdio.h>

void log_it(char *msg_buf) {
  printf("LOG: %s\n", msg_buf);
}

int main(void) {

  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);
    log_it(str);
  }
  else {
    str = "FILE OPENED";
    log_it(str);
  }  
  free(str);
  return 0;
}	

Compliant Code Example 1

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.  

Code Block
#include <stdlib.h>
#include <stdio.h>

void log_it(char *msg_buf) {
  printf("LOG: %s\n", msg_buf);
}

int main(void) {

  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);
    log_it(str);
    free(str);   /* only dynamic memory is freed */	
  }
  else {
    str = "FILE OPENED";
    log_it(str);
  }  
  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) {
  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;
}

...

Code Block
/* 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.

...