As noted in undefined behavior 169 of Annex J of [ISO/IEC 9899-1999], the behavior a program is undefined when
the pointer argument to the
freeorreallocfunction does not match a pointer earlier returned bycalloc,malloc, orrealloc, or the space has been deallocated by a call tofreeorrealloc.
Freeing memory multiple times has similar consequences to accessing memory after it is freed. (See rule MEM30-C. Do not access freed memory.) First, reading a pointer to deallocated memory is undefined because the pointer value is indeterminate and can have a trap representation. In the latter case, doing so can cause a hardware trap. When reading a freed pointer doesn't cause a trap, the underlying data structures that manage the heap can become corrupted in a way that can introduce security vulnerabilities into a program. These types of issues are referred to as double-free vulnerabilities. In practice, double-free vulnerabilities can be exploited to execute arbitrary code. One example of this is VU#623332, which describes a double-free vulnerability in the MIT Kerberos 5 function krb5_recvauth().
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
int f(size_t n) {
int error_condition = 0;
int *x = (int*)malloc(n * sizeof(int));
if (x == NULL)
return -1;
/* Use x and set error_condition on error. */
if (error_condition == 1) {
/* Handle error condition*/
free(x);
}
/* ... */
free(x);
return error_condition;
}
|
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
int f(size_t n) {
int error_condition = 0;
if (n > SIZE_MAX / sizeof(int)) {
errno = EOVERFLOW;
return -1;
}
int *x = (int*)malloc(n * sizeof(int));
if (x == NULL) {
/* Report allocation failure to caller. */
return -1;
}
/* Use x and set error_condition on error. */
if (error_condition != 0) {
/* Handle error condition and proceed. */
}
free(x);
return error_condition;
}
|
Note that this solution checks for numeric overflow. (See rule INT32-C. Ensure that operations on signed integers do not result in overflow.)
Noncompliant Code Example (realloc())
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
/* p is a pointer to dynamically allocated memory */
p2 = realloc(p, size);
if (p2 == NULL) {
free(p); /* p may be indeterminate when (size == 0) */
return;
}
|
According to the C99 standard [ISO/IEC 9899-1999] (7.20.3):
If the size of the space requested is zero, the behavior is implementation defined: either a null pointer is returned, or the behavior is as if the size were some nonzero value, except that the returned pointer shall not be used to access an object.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
/* p is a pointer to dynamically allocated memory */
if (size) {
p2 = realloc(p, size);
if (p2 == NULL) {
free(p);
return;
}
}
else {
free(p);
return;
}
|
...
CERT C Secure Coding Standard: MEM04-C. Do not perform zero length allocations
ISO/IEC TR 17961 (Draft) Forming or using out-of-bounds pointers or array subscripts [invptr]
ISO/IEC TR 24772 "XYK Dangling Reference to Heap" and "XYL Memory Leak"
MITRE CWE: CWE-415, "Double Free"
Bibliography
[MIT 2005]
[OWASP, Double Free]
[Viega 2005] "Doubly freeing memory"
[VU#623332]
...