From 5e3f9e57b6ac3de83bc4e517d411e896abd4e37d Mon Sep 17 00:00:00 2001 From: Edward Thomson Date: Fri, 10 Jul 2020 08:57:05 +0100 Subject: alloc: set up an allocator that fails before library init We require the library to be initialized with git_libgit2_init before it is functional. However, if a user tries to uses the library without doing so - as they might when getting started with the library for the first time - we will likely crash. This commit introduces some guard rails - now instead of having _no_ allocator by default, we'll have an allocator that always fails, and never tries to set an error message (since the thread-local state is set up by git_libgit2_init). We've modified the error retrieval function to (try to) ensure that the library has been initialized before getting the thread-local error message. (Unfortunately, we cannot determine if the thread local storage has actually been configured, this does require initialization by git_libgit2_init. But a naive attempt should be good enough for most cases.) --- src/alloc.c | 16 +++++++- src/allocators/failalloc.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++ src/allocators/failalloc.h | 23 ++++++++++++ src/errors.c | 10 +++++ 4 files changed, 139 insertions(+), 2 deletions(-) create mode 100644 src/allocators/failalloc.c create mode 100644 src/allocators/failalloc.h diff --git a/src/alloc.c b/src/alloc.c index 6972e7b59..9ec90297f 100644 --- a/src/alloc.c +++ b/src/alloc.c @@ -8,6 +8,7 @@ #include "alloc.h" #include "runtime.h" +#include "allocators/failalloc.h" #include "allocators/stdalloc.h" #include "allocators/win32_crtdbg.h" @@ -16,7 +17,18 @@ # include "win32/w32_crtdbg_stacktrace.h" #endif -git_allocator git__allocator; +/* Fail any allocation until git_libgit2_init is called. */ +git_allocator git__allocator = { + git_failalloc_malloc, + git_failalloc_calloc, + git_failalloc_strdup, + git_failalloc_strndup, + git_failalloc_substrdup, + git_failalloc_realloc, + git_failalloc_reallocarray, + git_failalloc_mallocarray, + git_failalloc_free +}; static int setup_default_allocator(void) { @@ -49,7 +61,7 @@ int git_allocator_global_init(void) * We don't want to overwrite any allocator which has been set before * the init function is called. */ - if (git__allocator.gmalloc != NULL) + if (git__allocator.gmalloc != git_failalloc_malloc) return 0; return setup_default_allocator(); diff --git a/src/allocators/failalloc.c b/src/allocators/failalloc.c new file mode 100644 index 000000000..5257d1dec --- /dev/null +++ b/src/allocators/failalloc.c @@ -0,0 +1,92 @@ +/* + * 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 "failalloc.h" + +void *git_failalloc_malloc(size_t len, const char *file, int line) +{ + GIT_UNUSED(len); + GIT_UNUSED(file); + GIT_UNUSED(line); + + 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) +{ + GIT_UNUSED(ptr); + GIT_UNUSED(size); + GIT_UNUSED(file); + GIT_UNUSED(line); + + 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) +{ + GIT_UNUSED(ptr); +} diff --git a/src/allocators/failalloc.h b/src/allocators/failalloc.h new file mode 100644 index 000000000..6115e51e7 --- /dev/null +++ b/src/allocators/failalloc.h @@ -0,0 +1,23 @@ +/* + * 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_failalloc_h__ +#define INCLUDE_allocators_failalloc_h__ + +#include "common.h" + +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_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); + +#endif diff --git a/src/errors.c b/src/errors.c index d4da50da8..95a720b9a 100644 --- a/src/errors.c +++ b/src/errors.c @@ -10,6 +10,7 @@ #include "threadstate.h" #include "posix.h" #include "buffer.h" +#include "libgit2.h" /******************************************** * New error handling @@ -20,6 +21,11 @@ static git_error g_git_oom_error = { GIT_ERROR_NOMEMORY }; +static git_error g_git_uninitialized_error = { + "libgit2 has not been initialized; you must call git_libgit2_init", + GIT_ERROR_INVALID +}; + static void set_error_from_buffer(int error_class) { git_error *error = &GIT_THREADSTATE->error_t; @@ -131,6 +137,10 @@ void git_error_clear(void) const git_error *git_error_last(void) { + /* If the library is not initialized, return a static error. */ + if (!git_libgit2_init_count()) + return &g_git_uninitialized_error; + return GIT_THREADSTATE->last_error; } -- cgit v1.2.1