Skip to content

Commit 3603cb0

Browse files
Edward Thomsonethomson
authored andcommitted
git__*allocarray: safer realloc and malloc
Introduce git__reallocarray that checks the product of the number of elements and element size for overflow before allocation. Also introduce git__mallocarray that behaves like calloc, but without the `c`. (It does not zero memory, for those truly worried about every cycle.)
1 parent 15d54fd commit 3603cb0

File tree

7 files changed

+32
-23
lines changed

7 files changed

+32
-23
lines changed

src/array.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,7 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
5757
new_size = a->size * 3 / 2;
5858
}
5959

60-
if (GIT_ALLOC_OVERFLOW_MULTIPLY(new_size, item_size) ||
61-
(new_array = git__realloc(a->ptr, new_size * item_size)) == NULL)
60+
if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL)
6261
goto on_oom;
6362

6463
a->ptr = new_array; a->asize = new_size; a->size++;

src/oid.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -261,8 +261,7 @@ struct git_oid_shorten {
261261

262262
static int resize_trie(git_oid_shorten *self, size_t new_size)
263263
{
264-
GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(trie_node));
265-
self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node));
264+
self->nodes = git__reallocarray(self->nodes, new_size, sizeof(trie_node));
266265
GITERR_CHECK_ALLOC(self->nodes);
267266

268267
if (new_size > self->size) {

src/pack-objects.c

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,8 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
205205
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc + 1024, 3 / 2);
206206
pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2;
207207

208-
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc, sizeof(*po));
209-
pb->object_list = git__realloc(pb->object_list,
210-
pb->nr_alloc * sizeof(*po));
208+
pb->object_list = git__reallocarray(pb->object_list,
209+
pb->nr_alloc, sizeof(*po));
211210
GITERR_CHECK_ALLOC(pb->object_list);
212211
rehash(pb);
213212
}
@@ -505,8 +504,7 @@ static git_pobject **compute_write_order(git_packbuilder *pb)
505504
unsigned int i, wo_end, last_untagged;
506505
git_pobject **wo;
507506

508-
if (GIT_ALLOC_OVERFLOW_MULTIPLY(pb->nr_objects, sizeof(*wo)) ||
509-
(wo = git__malloc(pb->nr_objects * sizeof(*wo))) == NULL) {
507+
if ((wo = git__mallocarray(pb->nr_objects, sizeof(*wo))) == NULL) {
510508
giterr_set_oom();
511509
return NULL;
512510
}
@@ -1102,8 +1100,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
11021100
return 0;
11031101
}
11041102

1105-
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_threads, sizeof(*p));
1106-
p = git__malloc(pb->nr_threads * sizeof(*p));
1103+
p = git__mallocarray(pb->nr_threads, sizeof(*p));
11071104
GITERR_CHECK_ALLOC(p);
11081105

11091106
/* Partition the work among the threads */
@@ -1254,8 +1251,7 @@ static int prepare_pack(git_packbuilder *pb)
12541251
if (pb->progress_cb)
12551252
pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload);
12561253

1257-
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_objects, sizeof(*delta_list));
1258-
delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list));
1254+
delta_list = git__mallocarray(pb->nr_objects, sizeof(*delta_list));
12591255
GITERR_CHECK_ALLOC(delta_list);
12601256

12611257
for (i = 0; i < pb->nr_objects; ++i) {

src/tsort.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,8 +186,7 @@ static int resize(struct tsort_store *store, size_t new_size)
186186
if (store->alloc < new_size) {
187187
void **tempstore;
188188

189-
GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *));
190-
tempstore = git__realloc(store->storage, new_size * sizeof(void *));
189+
tempstore = git__reallocarray(store->storage, new_size, sizeof(void *));
191190

192191
/**
193192
* Do not propagate on OOM; this will abort the sort and

src/util.h

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,28 @@ GIT_INLINE(void *) git__realloc(void *ptr, size_t size)
104104
return new_ptr;
105105
}
106106

107+
/**
108+
* Similar to `git__realloc`, except that it is suitable for reallocing an
109+
* array to a new number of elements of `nelem`, each of size `elsize`.
110+
* The total size calculation is checked for overflow.
111+
*/
112+
GIT_INLINE(void *) git__reallocarray(void *ptr, size_t nelem, size_t elsize)
113+
{
114+
void *new_ptr = NULL;
115+
if (GIT_ALLOC_OVERFLOW_MULTIPLY(nelem, elsize) ||
116+
!(new_ptr = realloc(ptr, nelem * elsize)))
117+
giterr_set_oom();
118+
return new_ptr;
119+
}
120+
121+
/**
122+
* Similar to `git__calloc`, except that it does not zero memory.
123+
*/
124+
GIT_INLINE(void *) git__mallocarray(size_t nelem, size_t elsize)
125+
{
126+
return git__reallocarray(NULL, nelem, elsize);
127+
}
128+
107129
GIT_INLINE(void) git__free(void *ptr)
108130
{
109131
free(ptr);

src/vector.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,9 @@ GIT_INLINE(size_t) compute_new_size(git_vector *v)
2929

3030
GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size)
3131
{
32-
size_t new_bytes;
3332
void *new_contents;
3433

35-
/* Check for overflow */
36-
GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *));
37-
new_bytes = new_size * sizeof(void *);
38-
39-
new_contents = git__realloc(v->contents, new_bytes);
34+
new_contents = git__reallocarray(v->contents, new_size, sizeof(void *));
4035
GITERR_CHECK_ALLOC(new_contents);
4136

4237
v->_alloc_size = new_size;

src/win32/utf-conv.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,8 +99,7 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
9999
return -1;
100100
}
101101

102-
if (GIT_ALLOC_OVERFLOW_MULTIPLY(utf16_size, sizeof(wchar_t)) ||
103-
!(*dest = git__malloc(utf16_size * sizeof(wchar_t)))) {
102+
if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) {
104103
errno = ENOMEM;
105104
return -1;
106105
}

0 commit comments

Comments
 (0)