Skip to content

Commit 0ef3242

Browse files
authored
Merge pull request libgit2#4576 from pks-t/pks/memory-allocator
Custom memory allocators
2 parents 422cd59 + 0f6348f commit 0ef3242

File tree

13 files changed

+461
-211
lines changed

13 files changed

+461
-211
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ v0.27 + 1
1313

1414
### API additions
1515

16+
* You can now swap out memory allocators via the
17+
`GIT_OPT_SET_ALLOCATOR` option with `git_libgit2_opts()`.
18+
1619
### API removals
1720

1821
### Breaking API changes

include/git2/common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ typedef enum {
183183
GIT_OPT_GET_WINDOWS_SHAREMODE,
184184
GIT_OPT_SET_WINDOWS_SHAREMODE,
185185
GIT_OPT_ENABLE_STRICT_HASH_VERIFICATION,
186+
GIT_OPT_SET_ALLOCATOR
186187
} git_libgit2_opt_t;
187188

188189
/**
@@ -345,6 +346,12 @@ typedef enum {
345346
* > additional checksum calculation on each object. This defaults
346347
* > to enabled.
347348
*
349+
* opts(GIT_OPT_SET_ALLOCATOR, git_allocator *allocator)
350+
*
351+
* > Set the memory allocator to a different memory allocator. This
352+
* > allocator will then be used to make all memory allocations for
353+
* > libgit2 operations.
354+
*
348355
* @param option Option key
349356
* @param ... value to set the option
350357
* @return 0 on success, <0 on failure

include/git2/sys/alloc.h

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#ifndef INCLUDE_sys_git_alloc_h__
9+
#define INCLUDE_sys_git_alloc_h__
10+
11+
#include "git2/common.h"
12+
13+
GIT_BEGIN_DECL
14+
15+
/**
16+
* An instance for a custom memory allocator
17+
*
18+
* Setting the pointers of this structure allows the developer to implement
19+
* custom memory allocators. The global memory allocator can be set by using
20+
* "GIT_OPT_SET_ALLOCATOR" with the `git_libgit2_opts` function. Keep in mind
21+
* that all fields need to be set to a proper function.
22+
*/
23+
typedef struct {
24+
/* Allocate `n` bytes of memory */
25+
void *(*gmalloc)(size_t n, const char *file, int line);
26+
27+
/*
28+
* Allocate memory for an array of `nelem` elements, where each element
29+
* has a size of `elsize`. Returned memory shall be initialized to
30+
* all-zeroes
31+
*/
32+
void *(*gcalloc)(size_t nelem, size_t elsize, const char *file, int line);
33+
34+
/* Allocate memory for the string `str` and duplicate its contents. */
35+
char *(*gstrdup)(const char *str, const char *file, int line);
36+
37+
/*
38+
* Equivalent to the `gstrdup` function, but only duplicating at most
39+
* `n + 1` bytes
40+
*/
41+
char *(*gstrndup)(const char *str, size_t n, const char *file, int line);
42+
43+
/*
44+
* Equivalent to `gstrndup`, but will always duplicate exactly `n` bytes
45+
* of `str`. Thus, out of bounds reads at `str` may happen.
46+
*/
47+
char *(*gsubstrdup)(const char *str, size_t n, const char *file, int line);
48+
49+
/*
50+
* This function shall deallocate the old object `ptr` and return a
51+
* pointer to a new object that has the size specified by `size`. In
52+
* case `ptr` is `NULL`, a new array shall be allocated.
53+
*/
54+
void *(*grealloc)(void *ptr, size_t size, const char *file, int line);
55+
56+
/*
57+
* This function shall be equivalent to `grealloc`, but allocating
58+
* `neleme * elsize` bytes.
59+
*/
60+
void *(*greallocarray)(void *ptr, size_t nelem, size_t elsize, const char *file, int line);
61+
62+
/*
63+
* This function shall allocate a new array of `nelem` elements, where
64+
* each element has a size of `elsize` bytes.
65+
*/
66+
void *(*gmallocarray)(size_t nelem, size_t elsize, const char *file, int line);
67+
68+
/*
69+
* This function shall free the memory pointed to by `ptr`. In case
70+
* `ptr` is `NULL`, this shall be a no-op.
71+
*/
72+
void (*gfree)(void *ptr);
73+
} git_allocator;
74+
75+
/**
76+
* Initialize the allocator structure to use the `stdalloc` pointer.
77+
*
78+
* Set up the structure so that all of its members are using the standard
79+
* "stdalloc" allocator functions. The structure can then be used with
80+
* `git_allocator_setup`.
81+
*
82+
* @param allocator The allocator that is to be initialized.
83+
* @return An error code or 0.
84+
*/
85+
int git_stdalloc_init_allocator(git_allocator *allocator);
86+
87+
/**
88+
* Initialize the allocator structure to use the `crtdbg` pointer.
89+
*
90+
* Set up the structure so that all of its members are using the "crtdbg"
91+
* allocator functions. Note that this allocator is only available on Windows
92+
* platforms and only if libgit2 is being compiled with "-DMSVC_CRTDBG".
93+
*
94+
* @param allocator The allocator that is to be initialized.
95+
* @return An error code or 0.
96+
*/
97+
int git_win32_crtdbg_init_allocator(git_allocator *allocator);
98+
99+
GIT_END_DECL
100+
101+
#endif

src/alloc.c

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "alloc.h"
9+
10+
#if defined(GIT_MSVC_CRTDBG)
11+
# include "win32/w32_crtdbg_stacktrace.h"
12+
#else
13+
# include "stdalloc.h"
14+
#endif
15+
16+
git_allocator git__allocator;
17+
18+
int git_allocator_global_init(void)
19+
{
20+
#if defined(GIT_MSVC_CRTDBG)
21+
return git_win32_crtdbg_init_allocator(&git__allocator);
22+
#else
23+
return git_stdalloc_init_allocator(&git__allocator);
24+
#endif
25+
}
26+
27+
int git_allocator_setup(git_allocator *allocator)
28+
{
29+
memcpy(&git__allocator, allocator, sizeof(*allocator));
30+
return 0;
31+
}
32+
33+
#if !defined(GIT_MSVC_CRTDBG)
34+
int git_win32_crtdbg_init_allocator(git_allocator *allocator)
35+
{
36+
GIT_UNUSED(allocator);
37+
giterr_set(GIT_EINVALID, "crtdbg memory allocator not available");
38+
return -1;
39+
}
40+
#endif

src/alloc.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#ifndef INCLUDE_alloc_h__
9+
#define INCLUDE_alloc_h__
10+
11+
#include "git2/sys/alloc.h"
12+
13+
extern git_allocator git__allocator;
14+
15+
#define git__malloc(len) git__allocator.gmalloc(len, __FILE__, __LINE__)
16+
#define git__calloc(nelem, elsize) git__allocator.gcalloc(nelem, elsize, __FILE__, __LINE__)
17+
#define git__strdup(str) git__allocator.gstrdup(str, __FILE__, __LINE__)
18+
#define git__strndup(str, n) git__allocator.gstrndup(str, n, __FILE__, __LINE__)
19+
#define git__substrdup(str, n) git__allocator.gsubstrdup(str, n, __FILE__, __LINE__)
20+
#define git__realloc(ptr, size) git__allocator.grealloc(ptr, size, __FILE__, __LINE__)
21+
#define git__reallocarray(ptr, nelem, elsize) git__allocator.greallocarray(ptr, nelem, elsize, __FILE__, __LINE__)
22+
#define git__mallocarray(nelem, elsize) git__allocator.gmallocarray(nelem, elsize, __FILE__, __LINE__)
23+
#define git__free git__allocator.gfree
24+
25+
/**
26+
* This function is being called by our global setup routines to
27+
* initialize the standard allocator.
28+
*/
29+
int git_allocator_global_init(void);
30+
31+
/**
32+
* Switch out libgit2's global memory allocator
33+
*
34+
* @param allocator The new allocator that should be used. All function pointers
35+
* of it need to be set correctly.
36+
* @return An error code or 0.
37+
*/
38+
int git_allocator_setup(git_allocator *allocator);
39+
40+
#endif

src/global.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
#include "global.h"
99

10+
#include "alloc.h"
1011
#include "hash.h"
1112
#include "sysdir.h"
1213
#include "filter.h"
@@ -60,7 +61,8 @@ static int init_common(void)
6061
#endif
6162

6263
/* Initialize any other subsystems that have global state */
63-
if ((ret = git_hash_global_init()) == 0 &&
64+
if ((ret = git_allocator_global_init()) == 0 &&
65+
(ret = git_hash_global_init()) == 0 &&
6466
(ret = git_sysdir_global_init()) == 0 &&
6567
(ret = git_filter_global_init()) == 0 &&
6668
(ret = git_merge_driver_global_init()) == 0 &&

src/settings.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#endif
1717

1818
#include <git2.h>
19+
#include "alloc.h"
1920
#include "sysdir.h"
2021
#include "cache.h"
2122
#include "global.h"
@@ -260,6 +261,10 @@ int git_libgit2_opts(int key, ...)
260261
git_odb__strict_hash_verification = (va_arg(ap, int) != 0);
261262
break;
262263

264+
case GIT_OPT_SET_ALLOCATOR:
265+
error = git_allocator_setup(va_arg(ap, git_allocator *));
266+
break;
267+
263268
default:
264269
giterr_set(GITERR_INVALID, "invalid option key");
265270
error = -1;

src/stdalloc.c

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#include "stdalloc.h"
9+
10+
static void *stdalloc__malloc(size_t len, const char *file, int line)
11+
{
12+
void *ptr = malloc(len);
13+
14+
GIT_UNUSED(file);
15+
GIT_UNUSED(line);
16+
17+
if (!ptr) giterr_set_oom();
18+
return ptr;
19+
}
20+
21+
static void *stdalloc__calloc(size_t nelem, size_t elsize, const char *file, int line)
22+
{
23+
void *ptr = calloc(nelem, elsize);
24+
25+
GIT_UNUSED(file);
26+
GIT_UNUSED(line);
27+
28+
if (!ptr) giterr_set_oom();
29+
return ptr;
30+
}
31+
32+
static char *stdalloc__strdup(const char *str, const char *file, int line)
33+
{
34+
char *ptr = strdup(str);
35+
36+
GIT_UNUSED(file);
37+
GIT_UNUSED(line);
38+
39+
if (!ptr) giterr_set_oom();
40+
return ptr;
41+
}
42+
43+
static char *stdalloc__strndup(const char *str, size_t n, const char *file, int line)
44+
{
45+
size_t length = 0, alloclength;
46+
char *ptr;
47+
48+
length = p_strnlen(str, n);
49+
50+
if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
51+
!(ptr = stdalloc__malloc(alloclength, file, line)))
52+
return NULL;
53+
54+
if (length)
55+
memcpy(ptr, str, length);
56+
57+
ptr[length] = '\0';
58+
59+
return ptr;
60+
}
61+
62+
static char *stdalloc__substrdup(const char *start, size_t n, const char *file, int line)
63+
{
64+
char *ptr;
65+
size_t alloclen;
66+
67+
if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
68+
!(ptr = stdalloc__malloc(alloclen, file, line)))
69+
return NULL;
70+
71+
memcpy(ptr, start, n);
72+
ptr[n] = '\0';
73+
return ptr;
74+
}
75+
76+
static void *stdalloc__realloc(void *ptr, size_t size, const char *file, int line)
77+
{
78+
void *new_ptr = realloc(ptr, size);
79+
80+
GIT_UNUSED(file);
81+
GIT_UNUSED(line);
82+
83+
if (!new_ptr) giterr_set_oom();
84+
return new_ptr;
85+
}
86+
87+
static void *stdalloc__reallocarray(void *ptr, size_t nelem, size_t elsize, const char *file, int line)
88+
{
89+
size_t newsize;
90+
91+
GIT_UNUSED(file);
92+
GIT_UNUSED(line);
93+
94+
return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
95+
NULL : realloc(ptr, newsize);
96+
}
97+
98+
static void *stdalloc__mallocarray(size_t nelem, size_t elsize, const char *file, int line)
99+
{
100+
return stdalloc__reallocarray(NULL, nelem, elsize, file, line);
101+
}
102+
103+
static void stdalloc__free(void *ptr)
104+
{
105+
free(ptr);
106+
}
107+
108+
int git_stdalloc_init_allocator(git_allocator *allocator)
109+
{
110+
allocator->gmalloc = stdalloc__malloc;
111+
allocator->gcalloc = stdalloc__calloc;
112+
allocator->gstrdup = stdalloc__strdup;
113+
allocator->gstrndup = stdalloc__strndup;
114+
allocator->gsubstrdup = stdalloc__substrdup;
115+
allocator->grealloc = stdalloc__realloc;
116+
allocator->greallocarray = stdalloc__reallocarray;
117+
allocator->gmallocarray = stdalloc__mallocarray;
118+
allocator->gfree = stdalloc__free;
119+
return 0;
120+
}

src/stdalloc.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (C) the libgit2 contributors. All rights reserved.
3+
*
4+
* This file is part of libgit2, distributed under the GNU GPL v2 with
5+
* a Linking Exception. For full terms see the included COPYING file.
6+
*/
7+
8+
#ifndef INCLUDE_stdalloc_h__
9+
#define INCLUDE_stdalloc_h__
10+
11+
#include "alloc.h"
12+
13+
#include "common.h"
14+
15+
int git_stdalloc_init_allocator(git_allocator *allocator);
16+
17+
#endif

0 commit comments

Comments
 (0)