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.
This commit is contained in:
Edward Thomson
2024-04-18 20:47:45 +01:00
parent c7af393a48
commit aaed67f786
4 changed files with 92 additions and 11 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}