Commit 9dd1bfe8 by Edward Thomson

alloc: simplify pluggable allocators

Remove the number of functions that custom allocator users need to
provide; nobody should need to implement `substrdup`. Keep it to the
basics that are actually _needed_ for allocation (malloc, realloc,
free) and reimplement the rest ourselves.

In addition, move the failure check and error setting _out_ of the
custom allocators and into a wrapper so that users don't need to deal
with this. This also allows us to call our allocator (without the
wrapper) early so that it does not try to set an error on failure, which
may be important for bootstrapping.
parent 9d41a3fd
...@@ -25,28 +25,6 @@ typedef struct { ...@@ -25,28 +25,6 @@ typedef struct {
void * GIT_CALLBACK(gmalloc)(size_t n, const char *file, int line); void * GIT_CALLBACK(gmalloc)(size_t n, const char *file, int line);
/** /**
* Allocate memory for an array of `nelem` elements, where each element
* has a size of `elsize`. Returned memory shall be initialized to
* all-zeroes
*/
void * GIT_CALLBACK(gcalloc)(size_t nelem, size_t elsize, const char *file, int line);
/** Allocate memory for the string `str` and duplicate its contents. */
char * GIT_CALLBACK(gstrdup)(const char *str, const char *file, int line);
/**
* Equivalent to the `gstrdup` function, but only duplicating at most
* `n + 1` bytes
*/
char * GIT_CALLBACK(gstrndup)(const char *str, size_t n, const char *file, int line);
/**
* Equivalent to `gstrndup`, but will always duplicate exactly `n` bytes
* of `str`. Thus, out of bounds reads at `str` may happen.
*/
char * GIT_CALLBACK(gsubstrdup)(const char *str, size_t n, const char *file, int line);
/**
* This function shall deallocate the old object `ptr` and return a * This function shall deallocate the old object `ptr` and return a
* pointer to a new object that has the size specified by `size`. In * pointer to a new object that has the size specified by `size`. In
* case `ptr` is `NULL`, a new array shall be allocated. * case `ptr` is `NULL`, a new array shall be allocated.
...@@ -54,18 +32,6 @@ typedef struct { ...@@ -54,18 +32,6 @@ typedef struct {
void * GIT_CALLBACK(grealloc)(void *ptr, size_t size, const char *file, int line); void * GIT_CALLBACK(grealloc)(void *ptr, size_t size, const char *file, int line);
/** /**
* This function shall be equivalent to `grealloc`, but allocating
* `neleme * elsize` bytes.
*/
void * GIT_CALLBACK(greallocarray)(void *ptr, size_t nelem, size_t elsize, const char *file, int line);
/**
* This function shall allocate a new array of `nelem` elements, where
* each element has a size of `elsize` bytes.
*/
void * GIT_CALLBACK(gmallocarray)(size_t nelem, size_t elsize, const char *file, int line);
/**
* This function shall free the memory pointed to by `ptr`. In case * This function shall free the memory pointed to by `ptr`. In case
* `ptr` is `NULL`, this shall be a no-op. * `ptr` is `NULL`, this shall be a no-op.
*/ */
......
...@@ -15,16 +15,75 @@ ...@@ -15,16 +15,75 @@
/* Fail any allocation until git_libgit2_init is called. */ /* Fail any allocation until git_libgit2_init is called. */
git_allocator git__allocator = { git_allocator git__allocator = {
git_failalloc_malloc, git_failalloc_malloc,
git_failalloc_calloc,
git_failalloc_strdup,
git_failalloc_strndup,
git_failalloc_substrdup,
git_failalloc_realloc, git_failalloc_realloc,
git_failalloc_reallocarray,
git_failalloc_mallocarray,
git_failalloc_free git_failalloc_free
}; };
void *git__calloc(size_t nelem, size_t elsize)
{
size_t newsize;
void *ptr;
if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
return NULL;
if ((ptr = git__malloc(newsize)))
memset(ptr, 0, newsize);
return ptr;
}
void *git__reallocarray(void *ptr, size_t nelem, size_t elsize)
{
size_t newsize;
if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
return NULL;
return git__realloc(ptr, newsize);
}
void *git__mallocarray(size_t nelem, size_t elsize)
{
return git__reallocarray(NULL, nelem, elsize);
}
char *git__strdup(const char *str)
{
size_t len = strlen(str) + 1;
void *ptr = git__malloc(len);
if (ptr)
memcpy(ptr, str, len);
return ptr;
}
char *git__strndup(const char *str, size_t n)
{
size_t len = p_strnlen(str, n);
char *ptr = git__malloc(len + 1);
if (ptr) {
memcpy(ptr, str, len);
ptr[len] = '\0';
}
return ptr;
}
char *git__substrdup(const char *str, size_t n)
{
char *ptr = git__malloc(n + 1);
if (ptr) {
memcpy(ptr, str, n);
ptr[n] = '\0';
}
return ptr;
}
static int setup_default_allocator(void) static int setup_default_allocator(void)
{ {
#if defined(GIT_WIN32_LEAKCHECK) #if defined(GIT_WIN32_LEAKCHECK)
......
...@@ -10,17 +10,42 @@ ...@@ -10,17 +10,42 @@
#include "git2/sys/alloc.h" #include "git2/sys/alloc.h"
#include "git2_util.h"
extern git_allocator git__allocator; extern git_allocator git__allocator;
#define git__malloc(len) git__allocator.gmalloc(len, __FILE__, __LINE__) GIT_INLINE(void *) git__malloc(size_t len)
#define git__calloc(nelem, elsize) git__allocator.gcalloc(nelem, elsize, __FILE__, __LINE__) {
#define git__strdup(str) git__allocator.gstrdup(str, __FILE__, __LINE__) void *p = git__allocator.gmalloc(len, __FILE__, __LINE__);
#define git__strndup(str, n) git__allocator.gstrndup(str, n, __FILE__, __LINE__)
#define git__substrdup(str, n) git__allocator.gsubstrdup(str, n, __FILE__, __LINE__) if (!p)
#define git__realloc(ptr, size) git__allocator.grealloc(ptr, size, __FILE__, __LINE__) git_error_set_oom();
#define git__reallocarray(ptr, nelem, elsize) git__allocator.greallocarray(ptr, nelem, elsize, __FILE__, __LINE__)
#define git__mallocarray(nelem, elsize) git__allocator.gmallocarray(nelem, elsize, __FILE__, __LINE__) return p;
#define git__free git__allocator.gfree }
GIT_INLINE(void *) git__realloc(void *ptr, size_t size)
{
void *p = git__allocator.grealloc(ptr, size, __FILE__, __LINE__);
if (!p)
git_error_set_oom();
return p;
}
GIT_INLINE(void) git__free(void *ptr)
{
git__allocator.gfree(ptr);
}
extern void *git__calloc(size_t nelem, size_t elsize);
extern void *git__mallocarray(size_t nelem, size_t elsize);
extern void *git__reallocarray(void *ptr, size_t nelem, size_t elsize);
extern char *git__strdup(const char *str);
extern char *git__strndup(const char *str, size_t n);
extern char *git__substrdup(const char *str, size_t n);
/** /**
* This function is being called by our global setup routines to * This function is being called by our global setup routines to
......
...@@ -16,45 +16,6 @@ void *git_failalloc_malloc(size_t len, const char *file, int line) ...@@ -16,45 +16,6 @@ void *git_failalloc_malloc(size_t len, const char *file, int line)
return NULL; return NULL;
} }
void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line)
{
GIT_UNUSED(nelem);
GIT_UNUSED(elsize);
GIT_UNUSED(file);
GIT_UNUSED(line);
return NULL;
}
char *git_failalloc_strdup(const char *str, const char *file, int line)
{
GIT_UNUSED(str);
GIT_UNUSED(file);
GIT_UNUSED(line);
return NULL;
}
char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line)
{
GIT_UNUSED(str);
GIT_UNUSED(n);
GIT_UNUSED(file);
GIT_UNUSED(line);
return NULL;
}
char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line)
{
GIT_UNUSED(start);
GIT_UNUSED(n);
GIT_UNUSED(file);
GIT_UNUSED(line);
return NULL;
}
void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line) void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line)
{ {
GIT_UNUSED(ptr); GIT_UNUSED(ptr);
...@@ -65,27 +26,6 @@ void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line) ...@@ -65,27 +26,6 @@ void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line)
return NULL; return NULL;
} }
void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
{
GIT_UNUSED(ptr);
GIT_UNUSED(nelem);
GIT_UNUSED(elsize);
GIT_UNUSED(file);
GIT_UNUSED(line);
return NULL;
}
void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line)
{
GIT_UNUSED(nelem);
GIT_UNUSED(elsize);
GIT_UNUSED(file);
GIT_UNUSED(line);
return NULL;
}
void git_failalloc_free(void *ptr) void git_failalloc_free(void *ptr)
{ {
GIT_UNUSED(ptr); GIT_UNUSED(ptr);
......
...@@ -11,13 +11,7 @@ ...@@ -11,13 +11,7 @@
#include "git2_util.h" #include "git2_util.h"
extern void *git_failalloc_malloc(size_t len, const char *file, int line); extern void *git_failalloc_malloc(size_t len, const char *file, int line);
extern void *git_failalloc_calloc(size_t nelem, size_t elsize, const char *file, int line);
extern char *git_failalloc_strdup(const char *str, const char *file, int line);
extern char *git_failalloc_strndup(const char *str, size_t n, const char *file, int line);
extern char *git_failalloc_substrdup(const char *start, size_t n, const char *file, int line);
extern void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line); extern void *git_failalloc_realloc(void *ptr, size_t size, const char *file, int line);
extern void *git_failalloc_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line);
extern void *git_failalloc_mallocarray(size_t nelem, size_t elsize, const char *file, int line);
extern void git_failalloc_free(void *ptr); extern void git_failalloc_free(void *ptr);
#endif #endif
...@@ -9,8 +9,6 @@ ...@@ -9,8 +9,6 @@
static void *stdalloc__malloc(size_t len, const char *file, int line) static void *stdalloc__malloc(size_t len, const char *file, int line)
{ {
void *ptr;
GIT_UNUSED(file); GIT_UNUSED(file);
GIT_UNUSED(line); GIT_UNUSED(line);
...@@ -19,86 +17,11 @@ static void *stdalloc__malloc(size_t len, const char *file, int line) ...@@ -19,86 +17,11 @@ static void *stdalloc__malloc(size_t len, const char *file, int line)
return NULL; return NULL;
#endif #endif
ptr = malloc(len); return malloc(len);
if (!ptr)
git_error_set_oom();
return ptr;
}
static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line)
{
void *ptr;
GIT_UNUSED(file);
GIT_UNUSED(line);
#ifdef GIT_DEBUG_STRICT_ALLOC
if (!elsize || !nelem)
return NULL;
#endif
ptr = calloc(nelem, elsize);
if (!ptr)
git_error_set_oom();
return ptr;
}
static char *stdalloc__strdup(const char *str, const char *file, int line)
{
char *ptr;
GIT_UNUSED(file);
GIT_UNUSED(line);
ptr = strdup(str);
if (!ptr)
git_error_set_oom();
return ptr;
}
static char *stdalloc__strndup(const char *str, size_t n, const char *file, int line)
{
size_t length = 0, alloclength;
char *ptr;
length = p_strnlen(str, n);
if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
!(ptr = stdalloc__malloc(alloclength, file, line)))
return NULL;
if (length)
memcpy(ptr, str, length);
ptr[length] = '\0';
return ptr;
}
static char *stdalloc__substrdup(const char *start, size_t n, const char *file, int line)
{
char *ptr;
size_t alloclen;
if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
!(ptr = stdalloc__malloc(alloclen, file, line)))
return NULL;
memcpy(ptr, start, n);
ptr[n] = '\0';
return ptr;
} }
static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line) static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line)
{ {
void *new_ptr;
GIT_UNUSED(file); GIT_UNUSED(file);
GIT_UNUSED(line); GIT_UNUSED(line);
...@@ -107,27 +30,7 @@ static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int lin ...@@ -107,27 +30,7 @@ static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int lin
return NULL; return NULL;
#endif #endif
new_ptr = realloc(ptr, size); return realloc(ptr, size);
if (!new_ptr)
git_error_set_oom();
return new_ptr;
}
static void *stdalloc__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
{
size_t newsize;
if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
return NULL;
return stdalloc__realloc(ptr, newsize, file, line);
}
static void *stdalloc__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
{
return stdalloc__reallocarray(NULL, nelem, elsize, file, line);
} }
static void stdalloc__free(void *ptr) static void stdalloc__free(void *ptr)
...@@ -138,13 +41,7 @@ static void stdalloc__free(void *ptr) ...@@ -138,13 +41,7 @@ static void stdalloc__free(void *ptr)
int git_stdalloc_init_allocator(git_allocator *allocator) int git_stdalloc_init_allocator(git_allocator *allocator)
{ {
allocator->gmalloc = stdalloc__malloc; allocator->gmalloc = stdalloc__malloc;
allocator->gcalloc = stdalloc__calloc;
allocator->gstrdup = stdalloc__strdup;
allocator->gstrndup = stdalloc__strndup;
allocator->gsubstrdup = stdalloc__substrdup;
allocator->grealloc = stdalloc__realloc; allocator->grealloc = stdalloc__realloc;
allocator->greallocarray = stdalloc__reallocarray;
allocator->gmallocarray = stdalloc__mallocarray;
allocator->gfree = stdalloc__free; allocator->gfree = stdalloc__free;
return 0; return 0;
} }
...@@ -18,53 +18,6 @@ static void *leakcheck_malloc(size_t len, const char *file, int line) ...@@ -18,53 +18,6 @@ static void *leakcheck_malloc(size_t len, const char *file, int line)
return ptr; return ptr;
} }
static void *leakcheck_calloc(size_t nelem, size_t elsize, const char *file, int line)
{
void *ptr = _calloc_dbg(nelem, elsize, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
if (!ptr) git_error_set_oom();
return ptr;
}
static char *leakcheck_strdup(const char *str, const char *file, int line)
{
char *ptr = _strdup_dbg(str, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
if (!ptr) git_error_set_oom();
return ptr;
}
static char *leakcheck_strndup(const char *str, size_t n, const char *file, int line)
{
size_t length = 0, alloclength;
char *ptr;
length = p_strnlen(str, n);
if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
!(ptr = leakcheck_malloc(alloclength, file, line)))
return NULL;
if (length)
memcpy(ptr, str, length);
ptr[length] = '\0';
return ptr;
}
static char *leakcheck_substrdup(const char *start, size_t n, const char *file, int line)
{
char *ptr;
size_t alloclen;
if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
!(ptr = leakcheck_malloc(alloclen, file, line)))
return NULL;
memcpy(ptr, start, n);
ptr[n] = '\0';
return ptr;
}
static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int line) static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int line)
{ {
void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line); void *new_ptr = _realloc_dbg(ptr, size, _NORMAL_BLOCK, git_win32_leakcheck_stacktrace(1,file), line);
...@@ -72,21 +25,6 @@ static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int lin ...@@ -72,21 +25,6 @@ static void *leakcheck_realloc(void *ptr, size_t size, const char *file, int lin
return new_ptr; return new_ptr;
} }
static void *leakcheck_reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
{
size_t newsize;
if (GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize))
return NULL;
return leakcheck_realloc(ptr, newsize, file, line);
}
static void *leakcheck_mallocarray(size_t nelem, size_t elsize, const char *file, int line)
{
return leakcheck_reallocarray(NULL, nelem, elsize, file, line);
}
static void leakcheck_free(void *ptr) static void leakcheck_free(void *ptr)
{ {
free(ptr); free(ptr);
...@@ -95,13 +33,7 @@ static void leakcheck_free(void *ptr) ...@@ -95,13 +33,7 @@ static void leakcheck_free(void *ptr)
int git_win32_leakcheck_init_allocator(git_allocator *allocator) int git_win32_leakcheck_init_allocator(git_allocator *allocator)
{ {
allocator->gmalloc = leakcheck_malloc; allocator->gmalloc = leakcheck_malloc;
allocator->gcalloc = leakcheck_calloc;
allocator->gstrdup = leakcheck_strdup;
allocator->gstrndup = leakcheck_strndup;
allocator->gsubstrdup = leakcheck_substrdup;
allocator->grealloc = leakcheck_realloc; allocator->grealloc = leakcheck_realloc;
allocator->greallocarray = leakcheck_reallocarray;
allocator->gmallocarray = leakcheck_mallocarray;
allocator->gfree = leakcheck_free; allocator->gfree = leakcheck_free;
return 0; return 0;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment