 
                            ...
Kernighan and Ritchie also correct this error by storing a reference to p->next  in q before freeing p.:
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #include <stdlib.h>
 
struct node {
  int value;
  struct node *next;
};
 
void free_list(struct node *head) {
  struct node *q;
  for (struct node *p = head; p != NULL; p = q) {
    q = p->next;
    free(p);
  }
} | 
...
In this noncompliant example, a diagnostic is required because realloc() may free c_str1 when it returns a null pointer, resulting in c_str1 being freed twice.  The WG14 committee's proposed response to Defect Report #400 makes it implementation-defined whether the old object is deallocated if size is zero and memory for the new object is not allocated, and the current implementation of realloc() in glibc will free c_str1 and return a null pointer for zero byte allocations.  Freeing a pointer twice can result in a potentially exploitable vulnerability commonly referred to as a "double-free exploit" [Seacord 2013].
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #include <stdlib.h>
 
void f(char *c_str1, size_t size) {
  char *c_str2 = (char *)realloc(c_str1, size);
  if (c_str2 == NULL) {
    free(c_str1); // diagnostic required
    return;
  }
} | 
...
This compliant solution does not pass a size argument of zero to the realloc() function, eliminating the possibility of c_str1 being freed twice. :
| Code Block | ||||
|---|---|---|---|---|
| 
 | ||||
| #include <stdlib.h>
 
void f(char *c_str1, size_t size) {
  if (size != 0) {
    char *c_str2 = (char *)realloc(c_str1, size); 
    if (c_str2 == NULL) {
      free(c_str1); 
    }
  }
  return;
} | 
...
Freeing memory multiple times has similar consequences to accessing memory after it is freed. FirstFirst, reading a pointer to deallocated memory is undefined behavior because the pointer value is indeterminate and might be a trap representation. When reading a freed pointer doesn't cause a trap, the underlying data structures that manage the heap can become corrupted in a manner that can be exploited to execute arbitrary code. These coding errors are referred to as "double-free vulnerabilities".
Programmers should be wary when freeing memory in a loop or conditional statement; if coded incorrectly, these constructs can lead to double-free vulnerabilities. It is also a common error to misuse the realloc() function in a manner that results in double-free vulnerabilities. (See MEM04-C. Beware of zero-length allocations.)
...