Ensure Memory Safety
Memory safety vulnerabilities are among the most critical security issues in software development. They can lead to arbitrary code execution, data corruption, denial of service, and information disclosure. This guide covers common memory safety issues in C/C++ including double-free, use-after-free, and buffer overflow vulnerabilities.
Double Free (CWE-415)
Freeing memory twice can cause memory corruption, crashes, or allow attackers to execute arbitrary code.
Incorrect:
int bad_code() {
char *var = malloc(sizeof(char) * 10);
free(var);
free(var); // Double free vulnerability
return 0;
}Correct:
int safe_code() {
char *var = malloc(sizeof(char) * 10);
free(var);
var = NULL; // Set to NULL after free
free(var); // Safe: freeing NULL is a no-op
return 0;
}Use After Free (CWE-416)
Accessing memory after it has been freed can lead to crashes, data corruption, or code execution.
Incorrect:
typedef struct name {
char *myname;
void (*func)(char *str);
} NAME;
int bad_code() {
NAME *var;
var = (NAME *)malloc(sizeof(struct name));
free(var);
var->func("use after free"); // Accessing freed memory
return 0;
}Correct:
typedef struct name {
char *myname;
void (*func)(char *str);
} NAME;
int safe_code() {
NAME *var;
var = (NAME *)malloc(sizeof(struct name));
free(var);
var = NULL; // Prevents accidental reuse
// Any access to var now causes immediate crash (easier to debug)
return 0;
}Buffer Overflow (CWE-119, CWE-120)
Writing beyond buffer boundaries can overwrite adjacent memory, leading to crashes or code execution.
Incorrect:
void bad_code(char *user_input) {
char buffer[64];
strcpy(buffer, user_input); // No bounds checking
}Correct:
void safe_code(char *user_input) {
char buffer[64];
snprintf(buffer, sizeof(buffer), "%s", user_input); // Bounds-checked, always null-terminates
}Format String Vulnerabilities (CWE-134)
Using user-controlled format strings can allow attackers to read or write arbitrary memory.
Incorrect:
void bad_printf(char *user_input) {
printf(user_input); // User controls format string
}Correct:
void safe_printf(char *user_input) {
printf("%s", user_input); // Format string is fixed
}Prevention Best Practices
- Set pointers to NULL after freeing - Prevents use-after-free and double-free
- Use bounded string functions -
snprintfinstead ofstrcpy/sprintf(strncpyrequires manual null-termination — prefersnprintf) - Never use user input as format strings - Always use fixed format strings
- Validate array indices - Check bounds before accessing arrays
- Use static analysis tools - Semgrep, Coverity, or similar to detect issues
- Consider memory-safe languages - Rust, Go, or managed languages where appropriate