Commit 3603cb09 by Edward Thomson Committed by Edward Thomson

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.)
parent 15d54fdd
...@@ -57,8 +57,7 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size) ...@@ -57,8 +57,7 @@ GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
new_size = a->size * 3 / 2; new_size = a->size * 3 / 2;
} }
if (GIT_ALLOC_OVERFLOW_MULTIPLY(new_size, item_size) || if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL)
(new_array = git__realloc(a->ptr, new_size * item_size)) == NULL)
goto on_oom; goto on_oom;
a->ptr = new_array; a->asize = new_size; a->size++; a->ptr = new_array; a->asize = new_size; a->size++;
......
...@@ -261,8 +261,7 @@ struct git_oid_shorten { ...@@ -261,8 +261,7 @@ struct git_oid_shorten {
static int resize_trie(git_oid_shorten *self, size_t new_size) static int resize_trie(git_oid_shorten *self, size_t new_size)
{ {
GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(trie_node)); self->nodes = git__reallocarray(self->nodes, new_size, sizeof(trie_node));
self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node));
GITERR_CHECK_ALLOC(self->nodes); GITERR_CHECK_ALLOC(self->nodes);
if (new_size > self->size) { if (new_size > self->size) {
......
...@@ -205,9 +205,8 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid, ...@@ -205,9 +205,8 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc + 1024, 3 / 2); GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc + 1024, 3 / 2);
pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2; pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2;
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_alloc, sizeof(*po)); pb->object_list = git__reallocarray(pb->object_list,
pb->object_list = git__realloc(pb->object_list, pb->nr_alloc, sizeof(*po));
pb->nr_alloc * sizeof(*po));
GITERR_CHECK_ALLOC(pb->object_list); GITERR_CHECK_ALLOC(pb->object_list);
rehash(pb); rehash(pb);
} }
...@@ -505,8 +504,7 @@ static git_pobject **compute_write_order(git_packbuilder *pb) ...@@ -505,8 +504,7 @@ static git_pobject **compute_write_order(git_packbuilder *pb)
unsigned int i, wo_end, last_untagged; unsigned int i, wo_end, last_untagged;
git_pobject **wo; git_pobject **wo;
if (GIT_ALLOC_OVERFLOW_MULTIPLY(pb->nr_objects, sizeof(*wo)) || if ((wo = git__mallocarray(pb->nr_objects, sizeof(*wo))) == NULL) {
(wo = git__malloc(pb->nr_objects * sizeof(*wo))) == NULL) {
giterr_set_oom(); giterr_set_oom();
return NULL; return NULL;
} }
...@@ -1102,8 +1100,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list, ...@@ -1102,8 +1100,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
return 0; return 0;
} }
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_threads, sizeof(*p)); p = git__mallocarray(pb->nr_threads, sizeof(*p));
p = git__malloc(pb->nr_threads * sizeof(*p));
GITERR_CHECK_ALLOC(p); GITERR_CHECK_ALLOC(p);
/* Partition the work among the threads */ /* Partition the work among the threads */
...@@ -1254,8 +1251,7 @@ static int prepare_pack(git_packbuilder *pb) ...@@ -1254,8 +1251,7 @@ static int prepare_pack(git_packbuilder *pb)
if (pb->progress_cb) if (pb->progress_cb)
pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload); pb->progress_cb(GIT_PACKBUILDER_DELTAFICATION, 0, pb->nr_objects, pb->progress_cb_payload);
GITERR_CHECK_ALLOC_MULTIPLY(pb->nr_objects, sizeof(*delta_list)); delta_list = git__mallocarray(pb->nr_objects, sizeof(*delta_list));
delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list));
GITERR_CHECK_ALLOC(delta_list); GITERR_CHECK_ALLOC(delta_list);
for (i = 0; i < pb->nr_objects; ++i) { for (i = 0; i < pb->nr_objects; ++i) {
......
...@@ -186,8 +186,7 @@ static int resize(struct tsort_store *store, size_t new_size) ...@@ -186,8 +186,7 @@ static int resize(struct tsort_store *store, size_t new_size)
if (store->alloc < new_size) { if (store->alloc < new_size) {
void **tempstore; void **tempstore;
GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *)); tempstore = git__reallocarray(store->storage, new_size, sizeof(void *));
tempstore = git__realloc(store->storage, new_size * sizeof(void *));
/** /**
* Do not propagate on OOM; this will abort the sort and * Do not propagate on OOM; this will abort the sort and
......
...@@ -104,6 +104,28 @@ GIT_INLINE(void *) git__realloc(void *ptr, size_t size) ...@@ -104,6 +104,28 @@ GIT_INLINE(void *) git__realloc(void *ptr, size_t size)
return new_ptr; return new_ptr;
} }
/**
* Similar to `git__realloc`, except that it is suitable for reallocing an
* array to a new number of elements of `nelem`, each of size `elsize`.
* The total size calculation is checked for overflow.
*/
GIT_INLINE(void *) git__reallocarray(void *ptr, size_t nelem, size_t elsize)
{
void *new_ptr = NULL;
if (GIT_ALLOC_OVERFLOW_MULTIPLY(nelem, elsize) ||
!(new_ptr = realloc(ptr, nelem * elsize)))
giterr_set_oom();
return new_ptr;
}
/**
* Similar to `git__calloc`, except that it does not zero memory.
*/
GIT_INLINE(void *) git__mallocarray(size_t nelem, size_t elsize)
{
return git__reallocarray(NULL, nelem, elsize);
}
GIT_INLINE(void) git__free(void *ptr) GIT_INLINE(void) git__free(void *ptr)
{ {
free(ptr); free(ptr);
......
...@@ -29,14 +29,9 @@ GIT_INLINE(size_t) compute_new_size(git_vector *v) ...@@ -29,14 +29,9 @@ GIT_INLINE(size_t) compute_new_size(git_vector *v)
GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size) GIT_INLINE(int) resize_vector(git_vector *v, size_t new_size)
{ {
size_t new_bytes;
void *new_contents; void *new_contents;
/* Check for overflow */ new_contents = git__reallocarray(v->contents, new_size, sizeof(void *));
GITERR_CHECK_ALLOC_MULTIPLY(new_size, sizeof(void *));
new_bytes = new_size * sizeof(void *);
new_contents = git__realloc(v->contents, new_bytes);
GITERR_CHECK_ALLOC(new_contents); GITERR_CHECK_ALLOC(new_contents);
v->_alloc_size = new_size; v->_alloc_size = new_size;
......
...@@ -99,8 +99,7 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src) ...@@ -99,8 +99,7 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
return -1; return -1;
} }
if (GIT_ALLOC_OVERFLOW_MULTIPLY(utf16_size, sizeof(wchar_t)) || if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) {
!(*dest = git__malloc(utf16_size * sizeof(wchar_t)))) {
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }
......
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