You are viewing an old version of this page. View the current version.

Compare with Current View Page History

Version 1 Next »

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 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) a series error could occur.

Non-compliant Code Example 1

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.

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

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

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 Code Example 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)

  • No labels