From aaed67f78673d6fb213de5a58dd1ed08d2ab9db2 Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Thu, 18 Apr 2024 20:47:45 +0100 Subject: [PATCH] alloc: introduce debug allocators Instead of tweaking the `stdalloc` allocator when `GIT_DEBUG_STRICT_ALLOC` is defined, actually create a debugging allocator. This allows us to ensure that we are strict about things like not expecting `malloc(0)` to do something useful, but we can also introduce an excessively pedantic `realloc` implementation that _always_ creates a new buffer, throws away its original `ptr`, and overwrites the data that's there with garbage. This may be helpful to identify places that make assumptions about realloc. --- src/util/alloc.c | 5 ++- src/util/allocators/debugalloc.c | 71 ++++++++++++++++++++++++++++++++ src/util/allocators/debugalloc.h | 17 ++++++++ src/util/allocators/stdalloc.c | 10 ----- 4 files changed, 92 insertions(+), 11 deletions(-) create mode 100644 src/util/allocators/debugalloc.c create mode 100644 src/util/allocators/debugalloc.h diff --git a/src/util/alloc.c b/src/util/alloc.c index 6ec173d04..998b0aea1 100644 --- a/src/util/alloc.c +++ b/src/util/alloc.c @@ -8,8 +8,9 @@ #include "alloc.h" #include "runtime.h" -#include "allocators/failalloc.h" #include "allocators/stdalloc.h" +#include "allocators/debugalloc.h" +#include "allocators/failalloc.h" #include "allocators/win32_leakcheck.h" /* Fail any allocation until git_libgit2_init is called. */ @@ -88,6 +89,8 @@ static int setup_default_allocator(void) { #if defined(GIT_WIN32_LEAKCHECK) return git_win32_leakcheck_init_allocator(&git__allocator); +#elif defined(GIT_DEBUG_STRICT_ALLOC) + return git_debugalloc_init_allocator(&git__allocator); #else return git_stdalloc_init_allocator(&git__allocator); #endif diff --git a/src/util/allocators/debugalloc.c b/src/util/allocators/debugalloc.c new file mode 100644 index 000000000..acb002dbb --- /dev/null +++ b/src/util/allocators/debugalloc.c @@ -0,0 +1,71 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#include "debugalloc.h" + +static void *debugalloc__malloc(size_t len, const char *file, int line) +{ + void *ptr; + size_t total = len + sizeof(size_t); + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (!len || (ptr = malloc(total)) == NULL) + return NULL; + + memcpy(ptr, &len, sizeof(size_t)); + return ptr + sizeof(size_t); +} + +static void *debugalloc__realloc(void *ptr, size_t len, const char *file, int line) +{ + void *newptr; + size_t original_len; + size_t total = len + sizeof(size_t); + + GIT_UNUSED(file); + GIT_UNUSED(line); + + if (!len && !ptr) + return NULL; + + if (!len) { + free(ptr - sizeof(size_t)); + return NULL; + } + + if ((newptr = malloc(total)) == NULL) + return NULL; + + if (ptr) { + memcpy(&original_len, ptr - sizeof(size_t), sizeof(size_t)); + memcpy(newptr + sizeof(size_t), ptr, min(len, original_len)); + + memset(ptr - sizeof(size_t), 0xfd, original_len + sizeof(size_t)); + free(ptr - sizeof(size_t)); + } + + memcpy(newptr, &len, sizeof(size_t)); + return newptr + sizeof(size_t); +} + +static void debugalloc__free(void *ptr) +{ + if (!ptr) + return; + + free(ptr - sizeof(size_t)); +} + +int git_debugalloc_init_allocator(git_allocator *allocator) +{ + allocator->gmalloc = debugalloc__malloc; + allocator->grealloc = debugalloc__realloc; + allocator->gfree = debugalloc__free; + return 0; +} diff --git a/src/util/allocators/debugalloc.h b/src/util/allocators/debugalloc.h new file mode 100644 index 000000000..dea0ca31c --- /dev/null +++ b/src/util/allocators/debugalloc.h @@ -0,0 +1,17 @@ +/* + * Copyright (C) the libgit2 contributors. All rights reserved. + * + * This file is part of libgit2, distributed under the GNU GPL v2 with + * a Linking Exception. For full terms see the included COPYING file. + */ + +#ifndef INCLUDE_allocators_debugalloc_h__ +#define INCLUDE_allocators_debugalloc_h__ + +#include "git2_util.h" + +#include "alloc.h" + +int git_debugalloc_init_allocator(git_allocator *allocator); + +#endif diff --git a/src/util/allocators/stdalloc.c b/src/util/allocators/stdalloc.c index f2d72a7e6..65ec40fbe 100644 --- a/src/util/allocators/stdalloc.c +++ b/src/util/allocators/stdalloc.c @@ -12,11 +12,6 @@ static void *stdalloc__malloc(size_t len, const char *file, int line) GIT_UNUSED(file); GIT_UNUSED(line); -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!len) - return NULL; -#endif - return malloc(len); } @@ -25,11 +20,6 @@ static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int lin GIT_UNUSED(file); GIT_UNUSED(line); -#ifdef GIT_DEBUG_STRICT_ALLOC - if (!size) - return NULL; -#endif - return realloc(ptr, size); }