A simple, yet effective way to avoid double-free and access-freed-memory vulnerabilities is to set pointers to NULL after they have been freed. Calling free() on a NULL pointer results in no action being taken by free(). Thus, it is recommended that freed pointers be set to NULL to help eliminate memory related vulnerabilities.
Non-compliant Code Example 1
In this example, the type of a message is used to determine how to process the message itself. It is assumed that message_type is an integer and message is a pointer to an array of characters that were allocated dynanmically. If message_type equals value_1, the message is processed accordingly. A similar operation occurs when message_type equals value_2. However, if message_type == value_1 evaluates to true and message_type == value_2 also evaluates to true, then message will be freed twice resulting in an error.
if (message_type == value_1) {
/* Process message type 1 */
free(message);
}
/* ...*/
if (message_type == value_2) {
/* Process message type 2 */
free(message);
}
Non-compliant Code Example 1
As stated above, calling free() on a NULL pointer results in no action being taken by free(). By setting message equal to NULL after it has been freed, the double-free vulnerability has been eliminated.
if (message_type == value_1) {
/* Process message type 1 */
free(message);
message = NULL;
}
/* ...*/
if (message_type == value_2) {
/* Process message type 2 */
free(message);
message = NULL;
}
References
- ISO/IEC 9899-1999 Section 7.20.3.2 The free function
- Seacord 05 Chapter 4 Dynamic Memory Management
- Consistent Memory Management Conventions, Dan Plakosh