Versions Compared

Key

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

...

Wiki Markup
This example from Kernighan and Ritchie \[[Kernighan 88|AA. Bibliography#Kernighan 88]\] shows both the incorrect and correct techniques for removing items from a linked list. The incorrect solution, clearly marked as wrong in the book, is bad because {{p}} is deallocated before the {{p->next}} is executed, so {{p->next}} reads memory that has already been deallocated.

Code Block
bgColor#FFCCCC
langcpp
for (p = head; p != NULL; p = p->next)
    free(p);

...

Kernighan and Ritchie also show the correct solution. To correct this error, a reference to p->next is stored in q before freeing p.

Code Block
bgColor#ccccff
langcpp
for (p = head; p != NULL; p = q) {
  q = p->next;
  free(p);
}
head = NULL;

...

In this noncompliant code example, buff is written to after it has been deallocated. These vulnerabilities can be easily exploited to run arbitrary code with the permissions of the vulnerable process and are seldom this obvious. Typically, dynamic memory allocations and deallocations are far removed, making it difficult to recognize and diagnose such problems.

Code Block
bgColor#FFCCCC
langcpp
int main(int argc, const char *argv[]) {
  char *buff;

  buff = new char[BUFSIZ];
  // ...
  delete[] buff;
  // ...
  strncpy(buff, argv[1], BUFSIZ-1);
}

...

In this compliant solution the dynamically allocated memory isn't deallocated until it is no longer required.

Code Block
bgColor#ccccff
langcpp
int main(int argc, const char *argv[]) {
  char *buff;

  buff = new char[BUFSIZ];
  // ...
  strncpy(buff, argv[1], BUFSIZ-1);
  // ...
  delete[] buff;
  buff = nullptr;
}

...

In the following noncompliant code example, the dynamically allocated memory managed by the buff object is accessed after it has been implicitly deallocated by the object's destructor.

Code Block
bgColor#ffcccc
langcpp
int main(int argc, const char *argv[]) {
  const char *s = "";

  if (1 < argc) {
    std::unique_ptr<char[]> buff (new char [BUFSIZ]);
    // ...
    s = strncpy(buff.get(), argv[1], BUFSIZ-1);
  }

  std::cout << s << '\n';
}

...

In this compliant solution the lifetime of the buff object extends past the point the memory managed by the object is accessed.

Code Block
bgColor#ccccff
langcpp
int main(int argc, const char *argv[]) {
  std::unique_ptr<char[]> buff;
  const char *s = "";

  if (1 < argc) {
    buff.reset(new char [BUFSIZ]);
    // ...
    s = strncpy(buff.get(), argv[1], BUFSIZ-1);
  }

  std::cout << s << '\n';
}

...