linux
Pointer is set to NULL without freeing previously allocated memory
When NUMA is enabled and size > PAGE_SIZE, inet_ehash_locks_free() does not free the memory allocated for `x' but just set this pointer to NULL.
Bug fixed by commit 218ad12f42e
Type | MemoryLeak |
Config | "NUMA && (SMP || DEBUG_SPINLOCK || DEBUG_LOCK_ALLOC)" (2nd degree) |
Fix-in | code |
Location | include/net/ |
#define ENOMEM 12 /* Out of memory */ #define NULL (void*)0 extern void *malloc (unsigned long __size) __attribute__ ((__nothrow__ , __leaf__)) __attribute__ ((__malloc__)) ; extern void free (void *__ptr) __attribute__ ((__nothrow__ , __leaf__)); #define PAGE_SIZE 12 int *x = NULL; unsigned int size = PAGE_SIZE+1; int inet_ehash_locks_alloc() { #ifdef CONFIG_NUMA if (size > PAGE_SIZE) x = malloc(size); else #endif x = malloc(size); // (2) if (!x) return ENOMEM; return 0; } void inet_ehash_locks_free() { if (x) { #ifdef CONFIG_NUMA if (size > PAGE_SIZE) free(x); else #else free(x); #endif x = NULL; // (4) ERROR } } int main(void) { inet_ehash_locks_alloc(); // (1) inet_ehash_locks_free(); // (3) return 0; }
diff --git a/simple/218ad12.c b/simple/218ad12.c --- a/simple/218ad12.c +++ b/simple/218ad12.c @@ -30,9 +30,8 @@ if (size > PAGE_SIZE) free(x); else -#else - free(x); #endif + free(x); x = NULL; // (4) ERROR } }
#include <errno.h> #include <stdlib.h> #define PAGE_SIZE 12 int *x = NULL; unsigned int size = PAGE_SIZE+1; int main(int argc, char** argv) { // inet_ehash_locks_alloc(); #ifdef CONFIG_NUMA if (size > PAGE_SIZE) x = malloc(size); else #endif x = malloc(size); if (!x) return ENOMEM; // inet_ehash_locks_free(); if (x) { #ifdef CONFIG_NUMA if (size > PAGE_SIZE) free(x); else #else free(x); #endif x = NULL; // ERROR } return 0; }
. include/net/inet_hashtables.h:147:inet_ehash_locks_alloc() . 169: hashinfo->ehash_locks = kmalloc(size * sizeof(rwlock_t), GFP_KERNEL); . include/net/inet_hashtables.h:180:inet_ehash_locks_free() . 128: if (hashinfo->ehash_locks) . ERROR 192: hashinfo->ehash_locks = NULL;