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