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..44022cd78 --- /dev/null +++ b/src/util/allocators/debugalloc.c @@ -0,0 +1,73 @@ +/* + * 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) +{ + unsigned char *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) +{ + unsigned char *ptr = _ptr, *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) +{ + unsigned char *ptr = _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); } diff --git a/src/util/unix/realpath.c b/src/util/unix/realpath.c index 9e31a63b9..e1d2adb8d 100644 --- a/src/util/unix/realpath.c +++ b/src/util/unix/realpath.c @@ -16,17 +16,35 @@ char *p_realpath(const char *pathname, char *resolved) { - char *ret; - if ((ret = realpath(pathname, resolved)) == NULL) + char *result; + + if ((result = realpath(pathname, resolved)) == NULL) return NULL; #ifdef __OpenBSD__ /* The OpenBSD realpath function behaves differently, * figure out if the file exists */ - if (access(ret, F_OK) < 0) - ret = NULL; + if (access(ret, F_OK) < 0) { + if (!resolved) + free(result); + + return NULL; + } #endif - return ret; + + /* + * If resolved == NULL, the system has allocated the result + * string. We need to strdup this into _our_ allocator pool + * so that callers can free it with git__free. + */ + if (!resolved) { + char *dup = git__strdup(result); + free(result); + + result = dup; + } + + return result; } #endif diff --git a/tests/clar/clar_libgit2_alloc.c b/tests/clar/clar_libgit2_alloc.c index e93037923..54eacd543 100644 --- a/tests/clar/clar_libgit2_alloc.c +++ b/tests/clar/clar_libgit2_alloc.c @@ -104,7 +104,5 @@ void cl_alloc_limit(size_t bytes) void cl_alloc_reset(void) { - git_allocator stdalloc; - git_stdalloc_init_allocator(&stdalloc); - git_allocator_setup(&stdalloc); + git_allocator_setup(NULL); } diff --git a/tests/libgit2/checkout/conflict.c b/tests/libgit2/checkout/conflict.c index b2eb939dc..3539c8b2d 100644 --- a/tests/libgit2/checkout/conflict.c +++ b/tests/libgit2/checkout/conflict.c @@ -1095,7 +1095,7 @@ static void collect_progress( if (path == NULL) return; - git_vector_insert(paths, strdup(path)); + git_vector_insert(paths, git__strdup(path)); } void test_checkout_conflict__report_progress(void) diff --git a/tests/libgit2/checkout/icase.c b/tests/libgit2/checkout/icase.c index d77c7abd5..3769a9f9b 100644 --- a/tests/libgit2/checkout/icase.c +++ b/tests/libgit2/checkout/icase.c @@ -89,7 +89,7 @@ static void assert_name_is(const char *expected) if (start) cl_assert_equal_strn("/", actual + (start - 1), 1); - free(actual); + git__free(actual); } static int symlink_or_fake(git_repository *repo, const char *a, const char *b) diff --git a/tests/libgit2/remote/fetch.c b/tests/libgit2/remote/fetch.c index a5d3272c5..7d2d11e27 100644 --- a/tests/libgit2/remote/fetch.c +++ b/tests/libgit2/remote/fetch.c @@ -40,10 +40,10 @@ void test_remote_fetch__cleanup(void) { git_repository_free(repo2); cl_git_pass(git_futils_rmdir_r(repo1_path, NULL, GIT_RMDIR_REMOVE_FILES)); - free(repo1_path); + git__free(repo1_path); cl_git_pass(git_futils_rmdir_r(repo2_path, NULL, GIT_RMDIR_REMOVE_FILES)); - free(repo2_path); + git__free(repo2_path); }