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

Compare with Current View Page History

« Previous Version 2 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. 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, such as malloc(), 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