Unclear Memory Ownership
Multiple parts of the code believe they own the same memory allocation, leading to multiple calls to free() on the same pointer without coordination or ownership tracking.
Double free vulnerabilities occur when the same dynamically allocated memory pointer is freed twice without being reset or having clear ownership. This can corrupt the heap allocator's internal structures, leading to crashes, memory corruption, and potentially enabling remote code execution through heap exploitation techniques.
/* VULNERABLE: Double free in error handling */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// VULNERABLE: Function with multiple free paths
int vulnerable_process_data(const char* input) {
char* buffer = malloc(1024);
char* temp_buffer = malloc(512);
if (!buffer || !temp_buffer) {
// VULNERABLE: Free without checking if allocation succeeded
free(buffer);
free(temp_buffer);
return -1;
}
// Process data
if (strlen(input) > 1000) {
printf("Input too long\n");
free(buffer);
free(temp_buffer);
return -1;
}
strcpy(buffer, input);
// Some processing that might fail
if (process_internal(buffer, temp_buffer) < 0) {
free(buffer);
free(temp_buffer);
return -1;
}
// VULNERABLE: Normal path also frees
free(buffer);
free(temp_buffer);
return 0;
// VULNERABLE: If process_internal calls free() internally,
// this creates a double-free condition
}/* SECURE: Safe memory management patterns */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
// SECURE: Safe wrapper for free()
void safe_free(void** ptr) {
if (ptr && *ptr) {
free(*ptr);
*ptr = NULL; // Prevent double-free
}
}
// SECURE: Macro for safer memory management
#define SAFE_FREE(ptr) do { \
if (ptr) { \
free(ptr); \
ptr = NULL; \
} \
} while(0)
// SECURE: Function with proper cleanup
int secure_process_data(const char* input) {
char* buffer = NULL;
char* temp_buffer = NULL;
int result = -1;
// Check input parameters
if (!input) {
return -1;
}
// Check input length before allocation
if (strlen(input) > 1000) {
printf("Input too long\n");
return -1;
}
// Allocate memory
buffer = malloc(1024);
temp_buffer = malloc(512);
if (!buffer || !temp_buffer) {
goto cleanup; // Safe cleanup handles NULL pointers
}
// Initialize memory
memset(buffer, 0, 1024);
memset(temp_buffer, 0, 512);
// Safe string copy
strncpy(buffer, input, 1023);
buffer[1023] = '\0';
// Process data with error checking
if (secure_process_internal(buffer, temp_buffer) < 0) {
goto cleanup;
}
result = 0; // Success
cleanup:
// SECURE: Single cleanup point, safe for NULL pointers
SAFE_FREE(buffer);
SAFE_FREE(temp_buffer);
return result;
}The vulnerable example shows common double-free scenarios including unclear ownership and multiple cleanup paths. The secure alternative implements comprehensive memory safety patterns including NULL pointer checks, single cleanup points, and safe free macros to prevent double-free conditions.
Multiple parts of the code believe they own the same memory allocation, leading to multiple calls to free() on the same pointer without coordination or ownership tracking.
Sourcery automatically identifies memory corruption from double free of heap pointer in native code and many other security issues in your codebase.