fix possible crash on user deletion
[srvx.git] / src / alloc-srvx.c
index 91d9035d2ecd2a4aa7cc154786c18d3ab285527d..11de0fd637256199f0e22cd7e5d16246d65f16a2 100644 (file)
  */
 
 #include "common.h"
+#include "log.h"
 
 #undef malloc
 #undef free
 
-/* cookies for anybody who recognizes these bytes without help :) */
 #define ALLOC_MAGIC 0x1acf
 #define FREE_MAGIC  0xfc1d
+const char redzone[] = { '\x03', '\x47', '\x76', '\xc7' };
 
 struct alloc_header {
     unsigned int file_id : 8;
@@ -32,6 +33,7 @@ struct alloc_header {
 
 static char file_id_map[256][32];
 static unsigned int file_ids_used;
+unsigned long alloc_count, alloc_size;
 
 static int
 file_id_cmp(const void *a_, const void *b_)
@@ -57,43 +59,53 @@ srvx_malloc(const char *file, unsigned int line, size_t size)
 {
     struct alloc_header *block;
 
-    block = malloc(sizeof(*block) + size);
+    block = malloc(sizeof(*block) + size + sizeof(redzone));
     assert(block != NULL);
+    if (block->magic == ALLOC_MAGIC && block->file_id < file_ids_used) {
+        /* Only report the error, due to possible false positives. */
+        log_module(MAIN_LOG, LOG_WARNING, "Detected possible reallocation: %p (called by %s:%u/%lu; allocated by %u:%u/%u).",
+                   block, file, line, (unsigned long)size,
+                   block->file_id, block->line, block->size);
+    }
     memset(block, 0, sizeof(*block) + size);
+    memcpy((char*)(block + 1) + size, redzone, sizeof(redzone));
     block->file_id = get_file_id(file);
     block->line = line;
     block->size = size;
     block->magic = ALLOC_MAGIC;
+    alloc_count++;
+    alloc_size += size;
     return block + 1;
 }
 
 void *
 srvx_realloc(const char *file, unsigned int line, void *ptr, size_t size)
 {
-    struct alloc_header *block = NULL, *newblock;
+    struct alloc_header *block, *newblock;
 
-    if (ptr) {
-        block = (struct alloc_header *)ptr - 1;
-        assert(block->magic == ALLOC_MAGIC);
-        if (block->size >= size)
-            return block + 1;
-    }
+    if (!ptr)
+        return srvx_malloc(file, line, size);
 
-    newblock = malloc(sizeof(*newblock) + size);
+    verify(ptr);
+    block = (struct alloc_header *)ptr - 1;
+
+    if (block->size >= size)
+        return block + 1;
+
+    newblock = malloc(sizeof(*newblock) + size + sizeof(redzone));
     assert(newblock != NULL);
-    memset(newblock, 0, sizeof(*newblock) + size);
+    memset(newblock, 0, sizeof(*newblock));
+    memcpy(newblock + 1, block + 1, block->size);
+    memset((char*)(newblock + 1) + block->size, 0, size - block->size);
+    memcpy((char*)(newblock + 1) + size, redzone, sizeof(redzone));
     newblock->file_id = get_file_id(file);
     newblock->line = line;
     newblock->size = size;
     newblock->magic = ALLOC_MAGIC;
+    alloc_count++;
+    alloc_size += size;
 
-    if (ptr) {
-        memcpy(newblock + 1, block + 1, block->size);
-        size = block->size + sizeof(*block);
-        memset(block, 0, size);
-        block->magic = FREE_MAGIC;
-        free(block);
-    }
+    srvx_free(file, line, block + 1);
 
     return newblock + 1;
 }
@@ -111,18 +123,30 @@ srvx_strdup(const char *file, unsigned int line, const char *src)
 }
 
 void
-srvx_free(const char *file, unsigned int line, void *ptr)
+srvx_free(UNUSED_ARG(const char *file), UNUSED_ARG(unsigned int line), void *ptr)
 {
     struct alloc_header *block;
     size_t size;
 
     if (!ptr)
         return;
+    verify(ptr);
     block = (struct alloc_header *)ptr - 1;
-    assert(block->magic == ALLOC_MAGIC);
-    size = block->size + sizeof(*block);
-    memset(block, 0, size);
+    size = block->size;
+    memset(block + 1, 0xde, size);
     block->magic = FREE_MAGIC;
     free(block);
-    (void)file; (void)line;
+    alloc_count--;
+    alloc_size -= size;
+}
+
+void
+verify(const void *ptr)
+{
+    const struct alloc_header *header;
+    if (!ptr)
+        return;
+    header = (const struct alloc_header*)ptr - 1;
+    assert(header->magic == ALLOC_MAGIC);
+    assert(!memcmp((char*)(header + 1) + header->size, redzone, sizeof(redzone)));
 }