Merge pull request #2895 from ethomson/alloc_overflow

allocations: test for overflow of requested size
This commit is contained in:
Carlos Martín Nieto 2015-02-15 05:13:50 +01:00
commit a7fa970f8b
57 changed files with 888 additions and 296 deletions

View File

@ -23,7 +23,7 @@
* *
* typedef git_array_t(my_struct) my_struct_array_t; * typedef git_array_t(my_struct) my_struct_array_t;
*/ */
#define git_array_t(type) struct { type *ptr; uint32_t size, asize; } #define git_array_t(type) struct { type *ptr; size_t size, asize; }
#define GIT_ARRAY_INIT { NULL, 0, 0 } #define GIT_ARRAY_INIT { NULL, 0, 0 }
@ -45,15 +45,26 @@ typedef git_array_t(char) git_array_generic_t;
GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size) GIT_INLINE(void *) git_array_grow(void *_a, size_t item_size)
{ {
volatile git_array_generic_t *a = _a; volatile git_array_generic_t *a = _a;
uint32_t new_size = (a->size < 8) ? 8 : a->asize * 3 / 2; size_t new_size;
char *new_array = git__realloc(a->ptr, new_size * item_size); char *new_array;
if (!new_array) {
git_array_clear(*a); if (a->size < 8) {
return NULL; new_size = 8;
} else { } else {
if (GIT_MULTIPLY_SIZET_OVERFLOW(&new_size, a->size, 3))
goto on_oom;
new_size /= 2;
}
if ((new_array = git__reallocarray(a->ptr, new_size, item_size)) == NULL)
goto on_oom;
a->ptr = new_array; a->asize = new_size; a->size++; a->ptr = new_array; a->asize = new_size; a->size++;
return a->ptr + (a->size - 1) * item_size; return a->ptr + (a->size - 1) * item_size;
}
on_oom:
git_array_clear(*a);
return NULL;
} }
#define git_array_alloc(a) \ #define git_array_alloc(a) \

View File

@ -76,6 +76,10 @@ static git_blame_hunk* dup_hunk(git_blame_hunk *hunk)
hunk->lines_in_hunk, hunk->lines_in_hunk,
hunk->orig_start_line_number, hunk->orig_start_line_number,
hunk->orig_path); hunk->orig_path);
if (!newhunk)
return NULL;
git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id); git_oid_cpy(&newhunk->orig_commit_id, &hunk->orig_commit_id);
git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id); git_oid_cpy(&newhunk->final_commit_id, &hunk->final_commit_id);
newhunk->boundary = hunk->boundary; newhunk->boundary = hunk->boundary;
@ -221,6 +225,10 @@ static git_blame_hunk *split_hunk_in_vector(
new_line_count = hunk->lines_in_hunk - rel_line; new_line_count = hunk->lines_in_hunk - rel_line;
nh = new_hunk((uint16_t)(hunk->final_start_line_number+rel_line), (uint16_t)new_line_count, nh = new_hunk((uint16_t)(hunk->final_start_line_number+rel_line), (uint16_t)new_line_count,
(uint16_t)(hunk->orig_start_line_number+rel_line), hunk->orig_path); (uint16_t)(hunk->orig_start_line_number+rel_line), hunk->orig_path);
if (!nh)
return NULL;
git_oid_cpy(&nh->final_commit_id, &hunk->final_commit_id); git_oid_cpy(&nh->final_commit_id, &hunk->final_commit_id);
git_oid_cpy(&nh->orig_commit_id, &hunk->orig_commit_id); git_oid_cpy(&nh->orig_commit_id, &hunk->orig_commit_id);
@ -270,6 +278,10 @@ static git_blame_hunk* hunk_from_entry(git_blame__entry *e)
{ {
git_blame_hunk *h = new_hunk( git_blame_hunk *h = new_hunk(
e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path); e->lno+1, e->num_lines, e->s_lno+1, e->suspect->path);
if (!h)
return NULL;
git_oid_cpy(&h->final_commit_id, git_commit_id(e->suspect->commit)); git_oid_cpy(&h->final_commit_id, git_commit_id(e->suspect->commit));
git_oid_cpy(&h->orig_commit_id, git_commit_id(e->suspect->commit)); git_oid_cpy(&h->orig_commit_id, git_commit_id(e->suspect->commit));
git_signature_dup(&h->final_signature, git_commit_author(e->suspect->commit)); git_signature_dup(&h->final_signature, git_commit_author(e->suspect->commit));
@ -307,6 +319,8 @@ static int blame_internal(git_blame *blame)
blame->final_buf_size = git_blob_rawsize(blame->final_blob); blame->final_buf_size = git_blob_rawsize(blame->final_blob);
ent = git__calloc(1, sizeof(git_blame__entry)); ent = git__calloc(1, sizeof(git_blame__entry));
GITERR_CHECK_ALLOC(ent);
ent->num_lines = index_blob_lines(blame); ent->num_lines = index_blob_lines(blame);
ent->lno = blame->options.min_line - 1; ent->lno = blame->options.min_line - 1;
ent->num_lines = ent->num_lines - blame->options.min_line + 1; ent->num_lines = ent->num_lines - blame->options.min_line + 1;
@ -322,8 +336,9 @@ static int blame_internal(git_blame *blame)
cleanup: cleanup:
for (ent = blame->ent; ent; ) { for (ent = blame->ent; ent; ) {
git_blame__entry *e = ent->next; git_blame__entry *e = ent->next;
git_blame_hunk *h = hunk_from_entry(ent);
git_vector_insert(&blame->hunks, hunk_from_entry(ent)); git_vector_insert(&blame->hunks, h);
git_blame__free_entry(ent); git_blame__free_entry(ent);
ent = e; ent = e;
@ -392,11 +407,14 @@ static int buffer_hunk_cb(
if (!blame->current_hunk) { if (!blame->current_hunk) {
/* Line added at the end of the file */ /* Line added at the end of the file */
blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path); blame->current_hunk = new_hunk(wedge_line, 0, wedge_line, blame->path);
GITERR_CHECK_ALLOC(blame->current_hunk);
git_vector_insert(&blame->hunks, blame->current_hunk); git_vector_insert(&blame->hunks, blame->current_hunk);
} else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){ } else if (!hunk_starts_at_or_after_line(blame->current_hunk, wedge_line)){
/* If this hunk doesn't start between existing hunks, split a hunk up so it does */ /* If this hunk doesn't start between existing hunks, split a hunk up so it does */
blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk, blame->current_hunk = split_hunk_in_vector(&blame->hunks, blame->current_hunk,
wedge_line - blame->current_hunk->orig_start_line_number, true); wedge_line - blame->current_hunk->orig_start_line_number, true);
GITERR_CHECK_ALLOC(blame->current_hunk);
} }
return 0; return 0;
@ -425,6 +443,8 @@ static int buffer_line_cb(
/* Create a new buffer-blame hunk with this line */ /* Create a new buffer-blame hunk with this line */
shift_hunks_by(&blame->hunks, blame->current_diff_line, 1); shift_hunks_by(&blame->hunks, blame->current_diff_line, 1);
blame->current_hunk = new_hunk((uint16_t)blame->current_diff_line, 1, 0, blame->path); blame->current_hunk = new_hunk((uint16_t)blame->current_diff_line, 1, 0, blame->path);
GITERR_CHECK_ALLOC(blame->current_hunk);
git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL); git_vector_insert_sorted(&blame->hunks, blame->current_hunk, NULL);
} }
blame->current_diff_line++; blame->current_diff_line++;
@ -464,10 +484,14 @@ int git_blame_buffer(
assert(out && reference && buffer && buffer_len); assert(out && reference && buffer && buffer_len);
blame = git_blame__alloc(reference->repository, reference->options, reference->path); blame = git_blame__alloc(reference->repository, reference->options, reference->path);
GITERR_CHECK_ALLOC(blame);
/* Duplicate all of the hunk structures in the reference blame */ /* Duplicate all of the hunk structures in the reference blame */
git_vector_foreach(&reference->hunks, i, hunk) { git_vector_foreach(&reference->hunks, i, hunk) {
git_vector_insert(&blame->hunks, dup_hunk(hunk)); git_blame_hunk *h = dup_hunk(hunk);
GITERR_CHECK_ALLOC(h);
git_vector_insert(&blame->hunks, h);
} }
/* Diff to the reference blob */ /* Diff to the reference blob */

View File

@ -35,11 +35,15 @@ static void origin_decref(git_blame__origin *o)
/* Given a commit and a path in it, create a new origin structure. */ /* Given a commit and a path in it, create a new origin structure. */
static int make_origin(git_blame__origin **out, git_commit *commit, const char *path) static int make_origin(git_blame__origin **out, git_commit *commit, const char *path)
{ {
int error = 0;
git_blame__origin *o; git_blame__origin *o;
size_t path_len = strlen(path), alloc_len;
int error = 0;
o = git__calloc(1, sizeof(*o) + strlen(path) + 1); GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*o), path_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
o = git__calloc(1, alloc_len);
GITERR_CHECK_ALLOC(o); GITERR_CHECK_ALLOC(o);
o->commit = commit; o->commit = commit;
o->refcnt = 1; o->refcnt = 1;
strcpy(o->path, path); strcpy(o->path, path);

View File

@ -13,7 +13,7 @@ int git_buf_text_puts_escaped(
const char *esc_with) const char *esc_with)
{ {
const char *scan; const char *scan;
size_t total = 0, esc_len = strlen(esc_with), count; size_t total = 0, esc_len = strlen(esc_with), count, alloclen;
if (!string) if (!string)
return 0; return 0;
@ -29,7 +29,8 @@ int git_buf_text_puts_escaped(
scan += count; scan += count;
} }
if (git_buf_grow(buf, buf->size + total + 1) < 0) GITERR_CHECK_ALLOC_ADD(&alloclen, total, 1);
if (git_buf_grow_by(buf, alloclen) < 0)
return -1; return -1;
for (scan = string; *scan; ) { for (scan = string; *scan; ) {
@ -65,6 +66,7 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
const char *scan = src->ptr; const char *scan = src->ptr;
const char *scan_end = src->ptr + src->size; const char *scan_end = src->ptr + src->size;
const char *next = memchr(scan, '\r', src->size); const char *next = memchr(scan, '\r', src->size);
size_t new_size;
char *out; char *out;
assert(tgt != src); assert(tgt != src);
@ -73,8 +75,10 @@ int git_buf_text_crlf_to_lf(git_buf *tgt, const git_buf *src)
return git_buf_set(tgt, src->ptr, src->size); return git_buf_set(tgt, src->ptr, src->size);
/* reduce reallocs while in the loop */ /* reduce reallocs while in the loop */
if (git_buf_grow(tgt, src->size + 1) < 0) GITERR_CHECK_ALLOC_ADD(&new_size, src->size, 1);
if (git_buf_grow(tgt, new_size) < 0)
return -1; return -1;
out = tgt->ptr; out = tgt->ptr;
tgt->size = 0; tgt->size = 0;
@ -110,6 +114,7 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
const char *end = start + src->size; const char *end = start + src->size;
const char *scan = start; const char *scan = start;
const char *next = memchr(scan, '\n', src->size); const char *next = memchr(scan, '\n', src->size);
size_t alloclen;
assert(tgt != src); assert(tgt != src);
@ -117,13 +122,14 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
return git_buf_set(tgt, src->ptr, src->size); return git_buf_set(tgt, src->ptr, src->size);
/* attempt to reduce reallocs while in the loop */ /* attempt to reduce reallocs while in the loop */
if (git_buf_grow(tgt, src->size + (src->size >> 4) + 1) < 0) GITERR_CHECK_ALLOC_ADD(&alloclen, src->size, src->size >> 4);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
if (git_buf_grow(tgt, alloclen) < 0)
return -1; return -1;
tgt->size = 0; tgt->size = 0;
for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) { for (; next; scan = next + 1, next = memchr(scan, '\n', end - scan)) {
size_t copylen = next - scan; size_t copylen = next - scan;
size_t needsize = tgt->size + copylen + 2 + 1;
/* if we find mixed line endings, bail */ /* if we find mixed line endings, bail */
if (next > start && next[-1] == '\r') { if (next > start && next[-1] == '\r') {
@ -131,7 +137,8 @@ int git_buf_text_lf_to_crlf(git_buf *tgt, const git_buf *src)
return GIT_PASSTHROUGH; return GIT_PASSTHROUGH;
} }
if (tgt->asize < needsize && git_buf_grow(tgt, needsize) < 0) GITERR_CHECK_ALLOC_ADD(&alloclen, copylen, 3);
if (git_buf_grow_by(tgt, alloclen) < 0)
return -1; return -1;
if (next > scan) { if (next > scan) {

View File

@ -63,6 +63,14 @@ int git_buf_try_grow(
/* round allocation up to multiple of 8 */ /* round allocation up to multiple of 8 */
new_size = (new_size + 7) & ~7; new_size = (new_size + 7) & ~7;
if (new_size < buf->size) {
if (mark_oom)
buf->ptr = git_buf__oom;
giterr_set_oom();
return -1;
}
new_ptr = git__realloc(new_ptr, new_size); new_ptr = git__realloc(new_ptr, new_size);
if (!new_ptr) { if (!new_ptr) {
@ -93,6 +101,18 @@ int git_buf_grow(git_buf *buffer, size_t target_size)
return git_buf_try_grow(buffer, target_size, true, true); return git_buf_try_grow(buffer, target_size, true, true);
} }
int git_buf_grow_by(git_buf *buffer, size_t additional_size)
{
size_t newsize;
if (GIT_ADD_SIZET_OVERFLOW(&newsize, buffer->size, additional_size)) {
buffer->ptr = git_buf__oom;
return -1;
}
return git_buf_try_grow(buffer, newsize, true, true);
}
void git_buf_free(git_buf *buf) void git_buf_free(git_buf *buf)
{ {
if (!buf) return; if (!buf) return;
@ -127,11 +147,14 @@ void git_buf_clear(git_buf *buf)
int git_buf_set(git_buf *buf, const void *data, size_t len) int git_buf_set(git_buf *buf, const void *data, size_t len)
{ {
size_t alloclen;
if (len == 0 || data == NULL) { if (len == 0 || data == NULL) {
git_buf_clear(buf); git_buf_clear(buf);
} else { } else {
if (data != buf->ptr) { if (data != buf->ptr) {
ENSURE_SIZE(buf, len + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
ENSURE_SIZE(buf, alloclen);
memmove(buf->ptr, data, len); memmove(buf->ptr, data, len);
} }
@ -160,7 +183,9 @@ int git_buf_sets(git_buf *buf, const char *string)
int git_buf_putc(git_buf *buf, char c) int git_buf_putc(git_buf *buf, char c)
{ {
ENSURE_SIZE(buf, buf->size + 2); size_t new_size;
GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, 2);
ENSURE_SIZE(buf, new_size);
buf->ptr[buf->size++] = c; buf->ptr[buf->size++] = c;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
return 0; return 0;
@ -168,7 +193,10 @@ int git_buf_putc(git_buf *buf, char c)
int git_buf_putcn(git_buf *buf, char c, size_t len) int git_buf_putcn(git_buf *buf, char c, size_t len)
{ {
ENSURE_SIZE(buf, buf->size + len + 1); size_t new_size;
GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
ENSURE_SIZE(buf, new_size);
memset(buf->ptr + buf->size, c, len); memset(buf->ptr + buf->size, c, len);
buf->size += len; buf->size += len;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
@ -178,8 +206,13 @@ int git_buf_putcn(git_buf *buf, char c, size_t len)
int git_buf_put(git_buf *buf, const char *data, size_t len) int git_buf_put(git_buf *buf, const char *data, size_t len)
{ {
if (len) { if (len) {
size_t new_size;
assert(data); assert(data);
ENSURE_SIZE(buf, buf->size + len + 1);
GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
ENSURE_SIZE(buf, new_size);
memmove(buf->ptr + buf->size, data, len); memmove(buf->ptr + buf->size, data, len);
buf->size += len; buf->size += len;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
@ -201,8 +234,13 @@ int git_buf_encode_base64(git_buf *buf, const char *data, size_t len)
size_t extra = len % 3; size_t extra = len % 3;
uint8_t *write, a, b, c; uint8_t *write, a, b, c;
const uint8_t *read = (const uint8_t *)data; const uint8_t *read = (const uint8_t *)data;
size_t blocks = (len / 3) + !!extra, alloclen;
ENSURE_SIZE(buf, buf->size + 4 * ((len / 3) + !!extra) + 1); GITERR_CHECK_ALLOC_ADD(&blocks, blocks, 1);
GITERR_CHECK_ALLOC_MULTIPLY(&alloclen, blocks, 4);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, buf->size);
ENSURE_SIZE(buf, alloclen);
write = (uint8_t *)&buf->ptr[buf->size]; write = (uint8_t *)&buf->ptr[buf->size];
/* convert each run of 3 bytes into 4 output bytes */ /* convert each run of 3 bytes into 4 output bytes */
@ -253,10 +291,12 @@ int git_buf_decode_base64(git_buf *buf, const char *base64, size_t len)
{ {
size_t i; size_t i;
int8_t a, b, c, d; int8_t a, b, c, d;
size_t orig_size = buf->size; size_t orig_size = buf->size, new_size;
assert(len % 4 == 0); assert(len % 4 == 0);
ENSURE_SIZE(buf, buf->size + (len / 4 * 3) + 1); GITERR_CHECK_ALLOC_ADD(&new_size, (len / 4 * 3), buf->size);
GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
ENSURE_SIZE(buf, new_size);
for (i = 0; i < len; i += 4) { for (i = 0; i < len; i += 4) {
if ((a = BASE64_DECODE_VALUE(base64[i])) < 0 || if ((a = BASE64_DECODE_VALUE(base64[i])) < 0 ||
@ -284,7 +324,13 @@ static const char b85str[] =
int git_buf_encode_base85(git_buf *buf, const char *data, size_t len) int git_buf_encode_base85(git_buf *buf, const char *data, size_t len)
{ {
ENSURE_SIZE(buf, buf->size + (5 * ((len / 4) + !!(len % 4))) + 1); size_t blocks = (len / 4) + !!(len % 4), alloclen;
GITERR_CHECK_ALLOC_MULTIPLY(&alloclen, blocks, 5);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, buf->size);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
ENSURE_SIZE(buf, alloclen);
while (len) { while (len) {
uint32_t acc = 0; uint32_t acc = 0;
@ -317,9 +363,11 @@ int git_buf_encode_base85(git_buf *buf, const char *data, size_t len)
int git_buf_vprintf(git_buf *buf, const char *format, va_list ap) int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
{ {
size_t expected_size, new_size;
int len; int len;
const size_t expected_size = buf->size + (strlen(format) * 2);
GITERR_CHECK_ALLOC_MULTIPLY(&expected_size, strlen(format), 2);
GITERR_CHECK_ALLOC_ADD(&expected_size, expected_size, buf->size);
ENSURE_SIZE(buf, expected_size); ENSURE_SIZE(buf, expected_size);
while (1) { while (1) {
@ -345,7 +393,9 @@ int git_buf_vprintf(git_buf *buf, const char *format, va_list ap)
break; break;
} }
ENSURE_SIZE(buf, buf->size + len + 1); GITERR_CHECK_ALLOC_ADD(&new_size, buf->size, len);
GITERR_CHECK_ALLOC_ADD(&new_size, new_size, 1);
ENSURE_SIZE(buf, new_size);
} }
return 0; return 0;
@ -472,16 +522,20 @@ int git_buf_join_n(git_buf *buf, char separator, int nbuf, ...)
continue; continue;
segment_len = strlen(segment); segment_len = strlen(segment);
total_size += segment_len;
GITERR_CHECK_ALLOC_ADD(&total_size, total_size, segment_len);
if (segment_len == 0 || segment[segment_len - 1] != separator) if (segment_len == 0 || segment[segment_len - 1] != separator)
++total_size; /* space for separator */ GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1);
} }
va_end(ap); va_end(ap);
/* expand buffer if needed */ /* expand buffer if needed */
if (total_size == 0) if (total_size == 0)
return 0; return 0;
if (git_buf_grow(buf, buf->size + total_size + 1) < 0)
GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1);
if (git_buf_grow_by(buf, total_size) < 0)
return -1; return -1;
out = buf->ptr + buf->size; out = buf->ptr + buf->size;
@ -542,6 +596,7 @@ int git_buf_join(
{ {
size_t strlen_a = str_a ? strlen(str_a) : 0; size_t strlen_a = str_a ? strlen(str_a) : 0;
size_t strlen_b = strlen(str_b); size_t strlen_b = strlen(str_b);
size_t alloc_len;
int need_sep = 0; int need_sep = 0;
ssize_t offset_a = -1; ssize_t offset_a = -1;
@ -559,7 +614,10 @@ int git_buf_join(
if (str_a >= buf->ptr && str_a < buf->ptr + buf->size) if (str_a >= buf->ptr && str_a < buf->ptr + buf->size)
offset_a = str_a - buf->ptr; offset_a = str_a - buf->ptr;
if (git_buf_grow(buf, strlen_a + strlen_b + need_sep + 1) < 0) GITERR_CHECK_ALLOC_ADD(&alloc_len, strlen_a, strlen_b);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, need_sep);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
if (git_buf_grow(buf, alloc_len) < 0)
return -1; return -1;
assert(buf->ptr); assert(buf->ptr);
@ -587,7 +645,10 @@ int git_buf_join3(
const char *str_b, const char *str_b,
const char *str_c) const char *str_c)
{ {
size_t len_a = strlen(str_a), len_b = strlen(str_b), len_c = strlen(str_c); size_t len_a = strlen(str_a),
len_b = strlen(str_b),
len_c = strlen(str_c),
len_total;
int sep_a = 0, sep_b = 0; int sep_a = 0, sep_b = 0;
char *tgt; char *tgt;
@ -607,7 +668,12 @@ int git_buf_join3(
sep_b = (str_b[len_b - 1] != separator); sep_b = (str_b[len_b - 1] != separator);
} }
if (git_buf_grow(buf, len_a + sep_a + len_b + sep_b + len_c + 1) < 0) GITERR_CHECK_ALLOC_ADD(&len_total, len_a, sep_a);
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, len_b);
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, sep_b);
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, len_c);
GITERR_CHECK_ALLOC_ADD(&len_total, len_total, 1);
if (git_buf_grow(buf, len_total) < 0)
return -1; return -1;
tgt = buf->ptr; tgt = buf->ptr;
@ -660,22 +726,27 @@ int git_buf_splice(
const char *data, const char *data,
size_t nb_to_insert) size_t nb_to_insert)
{ {
assert(buf && char *splice_loc;
where <= git_buf_len(buf) && size_t new_size, alloc_size;
where + nb_to_remove <= git_buf_len(buf));
assert(buf && where <= buf->size && nb_to_remove <= buf->size - where);
splice_loc = buf->ptr + where;
/* Ported from git.git /* Ported from git.git
* https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176 * https://github.com/git/git/blob/16eed7c/strbuf.c#L159-176
*/ */
ENSURE_SIZE(buf, buf->size + nb_to_insert - nb_to_insert + 1); GITERR_CHECK_ALLOC_ADD(&new_size, (buf->size - nb_to_remove), nb_to_insert);
GITERR_CHECK_ALLOC_ADD(&alloc_size, new_size, 1);
ENSURE_SIZE(buf, alloc_size);
memmove(buf->ptr + where + nb_to_insert, memmove(splice_loc + nb_to_insert,
buf->ptr + where + nb_to_remove, splice_loc + nb_to_remove,
buf->size - where - nb_to_remove); buf->size - where - nb_to_remove);
memcpy(buf->ptr + where, data, nb_to_insert); memcpy(splice_loc, data, nb_to_insert);
buf->size = buf->size + nb_to_insert - nb_to_remove; buf->size = new_size;
buf->ptr[buf->size] = '\0'; buf->ptr[buf->size] = '\0';
return 0; return 0;
} }

View File

@ -36,6 +36,18 @@ GIT_INLINE(bool) git_buf_is_allocated(const git_buf *buf)
*/ */
extern void git_buf_init(git_buf *buf, size_t initial_size); extern void git_buf_init(git_buf *buf, size_t initial_size);
/**
* Resize the buffer allocation to make more space.
*
* This will attempt to grow the buffer to accommodate the additional size.
* It is similar to `git_buf_grow`, but performs the new size calculation,
* checking for overflow.
*
* Like `git_buf_grow`, if this is a user-supplied buffer, this will allocate
* a new buffer.
*/
extern int git_buf_grow_by(git_buf *buffer, size_t additional_size);
/** /**
* Attempt to grow the buffer to hold at least `target_size` bytes. * Attempt to grow the buffer to hold at least `target_size` bytes.
* *

View File

@ -17,6 +17,11 @@
# define GIT_INLINE(type) static inline type # define GIT_INLINE(type) static inline type
#endif #endif
/** Support for gcc/clang __has_builtin intrinsic */
#ifndef __has_builtin
# define __has_builtin(x) 0
#endif
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include <limits.h> #include <limits.h>
@ -58,6 +63,7 @@
#include "git2/types.h" #include "git2/types.h"
#include "git2/errors.h" #include "git2/errors.h"
#include "thread-utils.h" #include "thread-utils.h"
#include "integer.h"
#include <regex.h> #include <regex.h>
@ -174,6 +180,23 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v
GITERR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \ GITERR_CHECK_VERSION(&(VERSION), _tmpl.version, #TYPE); \
memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0) memcpy((PTR), &_tmpl, sizeof(_tmpl)); } while (0)
/** Check for additive overflow, setting an error if would occur. */
#define GIT_ADD_SIZET_OVERFLOW(out, one, two) \
(git__add_sizet_overflow(out, one, two) ? (giterr_set_oom(), 1) : 0)
/** Check for additive overflow, setting an error if would occur. */
#define GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize) \
(git__multiply_sizet_overflow(out, nelem, elsize) ? (giterr_set_oom(), 1) : 0)
/** Check for additive overflow, failing if it would occur. */
#define GITERR_CHECK_ALLOC_ADD(out, one, two) \
if (GIT_ADD_SIZET_OVERFLOW(out, one, two)) { return -1; }
/** Check for multiplicative overflow, failing if it would occur. */
#define GITERR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \
if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; }
/* NOTE: other giterr functions are in the public errors.h header file */ /* NOTE: other giterr functions are in the public errors.h header file */
#include "util.h" #include "util.h"

View File

@ -885,7 +885,7 @@ static char *reader_readline(struct reader *reader, bool skip_whitespace)
{ {
char *line = NULL; char *line = NULL;
char *line_src, *line_end; char *line_src, *line_end;
size_t line_len; size_t line_len, alloc_len;
line_src = reader->read_ptr; line_src = reader->read_ptr;
@ -903,9 +903,10 @@ static char *reader_readline(struct reader *reader, bool skip_whitespace)
line_len = line_end - line_src; line_len = line_end - line_src;
line = git__malloc(line_len + 1); if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, line_len, 1) ||
if (line == NULL) (line = git__malloc(alloc_len)) == NULL) {
return NULL; return NULL;
}
memcpy(line, line_src, line_len); memcpy(line, line_src, line_len);
@ -958,6 +959,8 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
int c, rpos; int c, rpos;
char *first_quote, *last_quote; char *first_quote, *last_quote;
git_buf buf = GIT_BUF_INIT; git_buf buf = GIT_BUF_INIT;
size_t quoted_len, alloc_len, base_name_len = strlen(base_name);
/* /*
* base_name is what came before the space. We should be at the * base_name is what came before the space. We should be at the
* first quotation mark, except for now, line isn't being kept in * first quotation mark, except for now, line isn't being kept in
@ -966,13 +969,17 @@ static int parse_section_header_ext(struct reader *reader, const char *line, con
first_quote = strchr(line, '"'); first_quote = strchr(line, '"');
last_quote = strrchr(line, '"'); last_quote = strrchr(line, '"');
quoted_len = last_quote - first_quote;
if (last_quote - first_quote == 0) { if (quoted_len == 0) {
set_parse_error(reader, 0, "Missing closing quotation mark in section header"); set_parse_error(reader, 0, "Missing closing quotation mark in section header");
return -1; return -1;
} }
git_buf_grow(&buf, strlen(base_name) + last_quote - first_quote + 2); GITERR_CHECK_ALLOC_ADD(&alloc_len, base_name_len, quoted_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
git_buf_grow(&buf, alloc_len);
git_buf_printf(&buf, "%s.", base_name); git_buf_printf(&buf, "%s.", base_name);
rpos = 0; rpos = 0;
@ -1029,6 +1036,7 @@ static int parse_section_header(struct reader *reader, char **section_out)
int name_length, c, pos; int name_length, c, pos;
int result; int result;
char *line; char *line;
size_t line_len;
line = reader_readline(reader, true); line = reader_readline(reader, true);
if (line == NULL) if (line == NULL)
@ -1042,7 +1050,8 @@ static int parse_section_header(struct reader *reader, char **section_out)
return -1; return -1;
} }
name = (char *)git__malloc((size_t)(name_end - line) + 1); GITERR_CHECK_ALLOC_ADD(&line_len, (size_t)(name_end - line), 1);
name = git__malloc(line_len);
GITERR_CHECK_ALLOC(name); GITERR_CHECK_ALLOC(name);
name_length = 0; name_length = 0;
@ -1604,11 +1613,15 @@ static char *escape_value(const char *ptr)
/* '\"' -> '"' etc */ /* '\"' -> '"' etc */
static char *fixup_line(const char *ptr, int quote_count) static char *fixup_line(const char *ptr, int quote_count)
{ {
char *str = git__malloc(strlen(ptr) + 1); char *str, *out, *esc;
char *out = str, *esc; size_t ptr_len = strlen(ptr), alloc_len;
if (str == NULL) if (GIT_ADD_SIZET_OVERFLOW(&alloc_len, ptr_len, 1) ||
(str = git__malloc(alloc_len)) == NULL) {
return NULL; return NULL;
}
out = str;
while (*ptr != '\0') { while (*ptr != '\0') {
if (*ptr == '"') { if (*ptr == '"') {

View File

@ -57,7 +57,7 @@ int git__delta_apply(
size_t delta_len) size_t delta_len)
{ {
const unsigned char *delta_end = delta + delta_len; const unsigned char *delta_end = delta + delta_len;
size_t base_sz, res_sz; size_t base_sz, res_sz, alloc_sz;
unsigned char *res_dp; unsigned char *res_dp;
/* Check that the base size matches the data we were given; /* Check that the base size matches the data we were given;
@ -74,7 +74,8 @@ int git__delta_apply(
return -1; return -1;
} }
res_dp = git__malloc(res_sz + 1); GITERR_CHECK_ALLOC_ADD(&alloc_sz, res_sz, 1);
res_dp = git__malloc(alloc_sz);
GITERR_CHECK_ALLOC(res_dp); GITERR_CHECK_ALLOC(res_dp);
res_dp[res_sz] = '\0'; res_dp[res_sz] = '\0';

View File

@ -119,6 +119,29 @@ struct git_delta_index {
struct index_entry *hash[GIT_FLEX_ARRAY]; struct index_entry *hash[GIT_FLEX_ARRAY];
}; };
static int lookup_index_alloc(
void **out, unsigned long *out_len, size_t entries, size_t hash_count)
{
size_t entries_len, hash_len, index_len;
GITERR_CHECK_ALLOC_MULTIPLY(&entries_len, entries, sizeof(struct index_entry));
GITERR_CHECK_ALLOC_MULTIPLY(&hash_len, hash_count, sizeof(struct index_entry *));
GITERR_CHECK_ALLOC_ADD(&index_len, sizeof(struct git_delta_index), entries_len);
GITERR_CHECK_ALLOC_ADD(&index_len, index_len, hash_len);
if (!git__is_ulong(index_len)) {
giterr_set(GITERR_NOMEMORY, "Overly large delta");
return -1;
}
*out = git__malloc(index_len);
GITERR_CHECK_ALLOC(*out);
*out_len = index_len;
return 0;
}
struct git_delta_index * struct git_delta_index *
git_delta_create_index(const void *buf, unsigned long bufsize) git_delta_create_index(const void *buf, unsigned long bufsize)
{ {
@ -148,13 +171,9 @@ git_delta_create_index(const void *buf, unsigned long bufsize)
hsize = 1 << i; hsize = 1 << i;
hmask = hsize - 1; hmask = hsize - 1;
/* allocate lookup index */ if (lookup_index_alloc(&mem, &memsize, entries, hsize) < 0)
memsize = sizeof(*index) +
sizeof(*hash) * hsize +
sizeof(*entry) * entries;
mem = git__malloc(memsize);
if (!mem)
return NULL; return NULL;
index = mem; index = mem;
mem = index->hash; mem = index->hash;
hash = mem; hash = mem;

View File

@ -1527,6 +1527,7 @@ int git_diff_format_email(
char *summary = NULL, *loc = NULL; char *summary = NULL, *loc = NULL;
bool ignore_marker; bool ignore_marker;
unsigned int format_flags = 0; unsigned int format_flags = 0;
size_t allocsize;
int error; int error;
assert(out && diff && opts); assert(out && diff && opts);
@ -1558,8 +1559,10 @@ int git_diff_format_email(
goto on_error; goto on_error;
} }
summary = git__calloc(offset + 1, sizeof(char)); GITERR_CHECK_ALLOC_ADD(&allocsize, offset, 1);
summary = git__calloc(allocsize, sizeof(char));
GITERR_CHECK_ALLOC(summary); GITERR_CHECK_ALLOC(summary);
strncpy(summary, opts->summary, offset); strncpy(summary, opts->summary, offset);
} }

View File

@ -158,6 +158,30 @@ static git_diff_driver_registry *git_repository_driver_registry(
return repo->diff_drivers; return repo->diff_drivers;
} }
static int diff_driver_alloc(
git_diff_driver **out, size_t *namelen_out, const char *name)
{
git_diff_driver *driver;
size_t driverlen = sizeof(git_diff_driver),
namelen = strlen(name),
alloclen;
GITERR_CHECK_ALLOC_ADD(&alloclen, driverlen, namelen);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
driver = git__calloc(1, alloclen);
GITERR_CHECK_ALLOC(driver);
memcpy(driver->name, name, namelen);
*out = driver;
if (namelen_out)
*namelen_out = namelen;
return 0;
}
static int git_diff_driver_builtin( static int git_diff_driver_builtin(
git_diff_driver **out, git_diff_driver **out,
git_diff_driver_registry *reg, git_diff_driver_registry *reg,
@ -166,7 +190,7 @@ static int git_diff_driver_builtin(
int error = 0; int error = 0;
git_diff_driver_definition *ddef = NULL; git_diff_driver_definition *ddef = NULL;
git_diff_driver *drv = NULL; git_diff_driver *drv = NULL;
size_t namelen, idx; size_t idx;
for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) { for (idx = 0; idx < ARRAY_SIZE(builtin_defs); ++idx) {
if (!strcasecmp(driver_name, builtin_defs[idx].name)) { if (!strcasecmp(driver_name, builtin_defs[idx].name)) {
@ -177,13 +201,10 @@ static int git_diff_driver_builtin(
if (!ddef) if (!ddef)
goto done; goto done;
namelen = strlen(ddef->name); if ((error = diff_driver_alloc(&drv, NULL, ddef->name)) < 0)
goto done;
drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1);
GITERR_CHECK_ALLOC(drv);
drv->type = DIFF_DRIVER_PATTERNLIST; drv->type = DIFF_DRIVER_PATTERNLIST;
memcpy(drv->name, ddef->name, namelen);
if (ddef->fns && if (ddef->fns &&
(error = diff_driver_add_patterns( (error = diff_driver_add_patterns(
@ -217,9 +238,9 @@ static int git_diff_driver_load(
int error = 0; int error = 0;
git_diff_driver_registry *reg; git_diff_driver_registry *reg;
git_diff_driver *drv = NULL; git_diff_driver *drv = NULL;
size_t namelen = strlen(driver_name); size_t namelen;
khiter_t pos; khiter_t pos;
git_config *cfg; git_config *cfg = NULL;
git_buf name = GIT_BUF_INIT; git_buf name = GIT_BUF_INIT;
const git_config_entry *ce; const git_config_entry *ce;
bool found_driver = false; bool found_driver = false;
@ -233,10 +254,10 @@ static int git_diff_driver_load(
return 0; return 0;
} }
drv = git__calloc(1, sizeof(git_diff_driver) + namelen + 1); if ((error = diff_driver_alloc(&drv, &namelen, driver_name)) < 0)
GITERR_CHECK_ALLOC(drv); goto done;
drv->type = DIFF_DRIVER_AUTO; drv->type = DIFF_DRIVER_AUTO;
memcpy(drv->name, driver_name, namelen);
/* if you can't read config for repo, just use default driver */ /* if you can't read config for repo, just use default driver */
if (git_repository_config_snapshot(&cfg, repo) < 0) { if (git_repository_config_snapshot(&cfg, repo) < 0) {

View File

@ -388,8 +388,13 @@ static int diff_patch_with_delta_alloc(
diff_patch_with_delta *pd; diff_patch_with_delta *pd;
size_t old_len = *old_path ? strlen(*old_path) : 0; size_t old_len = *old_path ? strlen(*old_path) : 0;
size_t new_len = *new_path ? strlen(*new_path) : 0; size_t new_len = *new_path ? strlen(*new_path) : 0;
size_t alloc_len;
*out = pd = git__calloc(1, sizeof(*pd) + old_len + new_len + 2); GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*pd), old_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, new_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
*out = pd = git__calloc(1, alloc_len);
GITERR_CHECK_ALLOC(pd); GITERR_CHECK_ALLOC(pd);
pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED; pd->patch.flags = GIT_DIFF_PATCH_ALLOCATED;

View File

@ -811,6 +811,7 @@ int git_diff_find_similar(
size_t num_deltas, num_srcs = 0, num_tgts = 0; size_t num_deltas, num_srcs = 0, num_tgts = 0;
size_t tried_srcs = 0, tried_tgts = 0; size_t tried_srcs = 0, tried_tgts = 0;
size_t num_rewrites = 0, num_updates = 0, num_bumped = 0; size_t num_rewrites = 0, num_updates = 0, num_bumped = 0;
size_t sigcache_size;
void **sigcache = NULL; /* cache of similarity metric file signatures */ void **sigcache = NULL; /* cache of similarity metric file signatures */
diff_find_match *tgt2src = NULL; diff_find_match *tgt2src = NULL;
diff_find_match *src2tgt = NULL; diff_find_match *src2tgt = NULL;
@ -831,7 +832,8 @@ int git_diff_find_similar(
if ((opts.flags & GIT_DIFF_FIND_ALL) == 0) if ((opts.flags & GIT_DIFF_FIND_ALL) == 0)
goto cleanup; goto cleanup;
sigcache = git__calloc(num_deltas * 2, sizeof(void *)); GITERR_CHECK_ALLOC_MULTIPLY(&sigcache_size, num_deltas, 2);
sigcache = git__calloc(sigcache_size, sizeof(void *));
GITERR_CHECK_ALLOC(sigcache); GITERR_CHECK_ALLOC(sigcache);
/* Label rename sources and targets /* Label rename sources and targets

View File

@ -194,7 +194,7 @@ static int write_deflate(git_filebuf *file, void *source, size_t len)
int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode) int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode)
{ {
int compression, error = -1; int compression, error = -1;
size_t path_len; size_t path_len, alloc_len;
/* opening an already open buffer is a programming error; /* opening an already open buffer is a programming error;
* assert that this never happens instead of returning * assert that this never happens instead of returning
@ -271,7 +271,8 @@ int git_filebuf_open(git_filebuf *file, const char *path, int flags, mode_t mode
GITERR_CHECK_ALLOC(file->path_original); GITERR_CHECK_ALLOC(file->path_original);
/* create the locking path by appending ".lock" to the original */ /* create the locking path by appending ".lock" to the original */
file->path_lock = git__malloc(path_len + GIT_FILELOCK_EXTLENGTH); GITERR_CHECK_ALLOC_ADD(&alloc_len, path_len, GIT_FILELOCK_EXTLENGTH);
file->path_lock = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(file->path_lock); GITERR_CHECK_ALLOC(file->path_lock);
memcpy(file->path_lock, file->path_original, path_len); memcpy(file->path_lock, file->path_original, path_len);
@ -407,8 +408,8 @@ int git_filebuf_reserve(git_filebuf *file, void **buffer, size_t len)
int git_filebuf_printf(git_filebuf *file, const char *format, ...) int git_filebuf_printf(git_filebuf *file, const char *format, ...)
{ {
va_list arglist; va_list arglist;
size_t space_left; size_t space_left, len, alloclen;
int len, res; int written, res;
char *tmp_buffer; char *tmp_buffer;
ENSURE_BUF_OK(file); ENSURE_BUF_OK(file);
@ -417,15 +418,16 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
do { do {
va_start(arglist, format); va_start(arglist, format);
len = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist); written = p_vsnprintf((char *)file->buffer + file->buf_pos, space_left, format, arglist);
va_end(arglist); va_end(arglist);
if (len < 0) { if (written < 0) {
file->last_error = BUFERR_MEM; file->last_error = BUFERR_MEM;
return -1; return -1;
} }
if ((size_t)len + 1 <= space_left) { len = written;
if (len + 1 <= space_left) {
file->buf_pos += len; file->buf_pos += len;
return 0; return 0;
} }
@ -435,19 +437,19 @@ int git_filebuf_printf(git_filebuf *file, const char *format, ...)
space_left = file->buf_size - file->buf_pos; space_left = file->buf_size - file->buf_pos;
} while ((size_t)len + 1 <= space_left); } while (len + 1 <= space_left);
tmp_buffer = git__malloc(len + 1); if (GIT_ADD_SIZET_OVERFLOW(&alloclen, len, 1) ||
if (!tmp_buffer) { !(tmp_buffer = git__malloc(alloclen))) {
file->last_error = BUFERR_MEM; file->last_error = BUFERR_MEM;
return -1; return -1;
} }
va_start(arglist, format); va_start(arglist, format);
len = p_vsnprintf(tmp_buffer, len + 1, format, arglist); written = p_vsnprintf(tmp_buffer, len + 1, format, arglist);
va_end(arglist); va_end(arglist);
if (len < 0) { if (written < 0) {
git__free(tmp_buffer); git__free(tmp_buffer);
file->last_error = BUFERR_MEM; file->last_error = BUFERR_MEM;
return -1; return -1;

View File

@ -124,10 +124,17 @@ mode_t git_futils_canonical_mode(mode_t raw_mode)
int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len) int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
{ {
ssize_t read_size = 0; ssize_t read_size = 0;
size_t alloc_len;
git_buf_clear(buf); git_buf_clear(buf);
if (git_buf_grow(buf, len + 1) < 0) if (!git__is_ssizet(len)) {
giterr_set(GITERR_INVALID, "Read too large.");
return -1;
}
GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
if (git_buf_grow(buf, alloc_len) < 0)
return -1; return -1;
/* p_read loops internally to read len bytes */ /* p_read loops internally to read len bytes */
@ -449,7 +456,13 @@ int git_futils_mkdir_ext(
} }
if (opts->dir_map && opts->pool) { if (opts->dir_map && opts->pool) {
char *cache_path = git_pool_malloc(opts->pool, make_path.size + 1); char *cache_path;
size_t alloc_size;
GITERR_CHECK_ALLOC_ADD(&alloc_size, make_path.size, 1);
if (!git__is_uint32(alloc_size))
return -1;
cache_path = git_pool_malloc(opts->pool, (uint32_t)alloc_size);
GITERR_CHECK_ALLOC(cache_path); GITERR_CHECK_ALLOC(cache_path);
memcpy(cache_path, make_path.ptr, make_path.size + 1); memcpy(cache_path, make_path.ptr, make_path.size + 1);
@ -708,7 +721,11 @@ static int cp_link(const char *from, const char *to, size_t link_size)
{ {
int error = 0; int error = 0;
ssize_t read_len; ssize_t read_len;
char *link_data = git__malloc(link_size + 1); char *link_data;
size_t alloc_size;
GITERR_CHECK_ALLOC_ADD(&alloc_size, link_size, 1);
link_data = git__malloc(alloc_size);
GITERR_CHECK_ALLOC(link_data); GITERR_CHECK_ALLOC(link_data);
read_len = p_readlink(from, link_data, link_size); read_len = p_readlink(from, link_data, link_size);

View File

@ -228,7 +228,7 @@ int git_filter_register(
const char *name, git_filter *filter, int priority) const char *name, git_filter *filter, int priority)
{ {
git_filter_def *fdef; git_filter_def *fdef;
size_t nattr = 0, nmatch = 0; size_t nattr = 0, nmatch = 0, alloc_len;
git_buf attrs = GIT_BUF_INIT; git_buf attrs = GIT_BUF_INIT;
assert(name && filter); assert(name && filter);
@ -245,8 +245,11 @@ int git_filter_register(
if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0) if (filter_def_scan_attrs(&attrs, &nattr, &nmatch, filter->attributes) < 0)
return -1; return -1;
fdef = git__calloc( GITERR_CHECK_ALLOC_MULTIPLY(&alloc_len, nattr, 2);
sizeof(git_filter_def) + 2 * nattr * sizeof(char *), 1); GITERR_CHECK_ALLOC_MULTIPLY(&alloc_len, alloc_len, sizeof(char *));
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, sizeof(git_filter_def));
fdef = git__calloc(1, alloc_len);
GITERR_CHECK_ALLOC(fdef); GITERR_CHECK_ALLOC(fdef);
fdef->filter_name = git__strdup(name); fdef->filter_name = git__strdup(name);
@ -377,9 +380,12 @@ static int filter_list_new(
git_filter_list **out, const git_filter_source *src) git_filter_list **out, const git_filter_source *src)
{ {
git_filter_list *fl = NULL; git_filter_list *fl = NULL;
size_t pathlen = src->path ? strlen(src->path) : 0; size_t pathlen = src->path ? strlen(src->path) : 0, alloclen;
fl = git__calloc(1, sizeof(git_filter_list) + pathlen + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_filter_list), pathlen);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
fl = git__calloc(1, alloclen);
GITERR_CHECK_ALLOC(fl); GITERR_CHECK_ALLOC(fl);
if (src->path) if (src->path)

View File

@ -770,7 +770,7 @@ static int index_entry_create(
git_repository *repo, git_repository *repo,
const char *path) const char *path)
{ {
size_t pathlen = strlen(path); size_t pathlen = strlen(path), alloclen;
struct entry_internal *entry; struct entry_internal *entry;
if (!git_path_isvalid(repo, path, if (!git_path_isvalid(repo, path,
@ -779,7 +779,9 @@ static int index_entry_create(
return -1; return -1;
} }
entry = git__calloc(sizeof(struct entry_internal) + pathlen + 1, 1); GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(struct entry_internal), pathlen);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
entry = git__calloc(1, alloclen);
GITERR_CHECK_ALLOC(entry); GITERR_CHECK_ALLOC(entry);
entry->pathlen = pathlen; entry->pathlen = pathlen;
@ -826,9 +828,16 @@ static int index_entry_init(
static git_index_reuc_entry *reuc_entry_alloc(const char *path) static git_index_reuc_entry *reuc_entry_alloc(const char *path)
{ {
size_t pathlen = strlen(path); size_t pathlen = strlen(path),
struct reuc_entry_internal *entry = structlen = sizeof(struct reuc_entry_internal),
git__calloc(sizeof(struct reuc_entry_internal) + pathlen + 1, 1); alloclen;
struct reuc_entry_internal *entry;
if (GIT_ADD_SIZET_OVERFLOW(&alloclen, structlen, pathlen) ||
GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1))
return NULL;
entry = git__calloc(1, alloclen);
if (!entry) if (!entry)
return NULL; return NULL;

96
src/integer.h Normal file
View File

@ -0,0 +1,96 @@
/*
* 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_integer_h__
#define INCLUDE_integer_h__
/** @return true if p fits into the range of a size_t */
GIT_INLINE(int) git__is_sizet(git_off_t p)
{
size_t r = (size_t)p;
return p == (git_off_t)r;
}
/** @return true if p fits into the range of an ssize_t */
GIT_INLINE(int) git__is_ssizet(size_t p)
{
ssize_t r = (ssize_t)p;
return p == (size_t)r;
}
/** @return true if p fits into the range of a uint32_t */
GIT_INLINE(int) git__is_uint32(size_t p)
{
uint32_t r = (uint32_t)p;
return p == (size_t)r;
}
/** @return true if p fits into the range of an unsigned long */
GIT_INLINE(int) git__is_ulong(git_off_t p)
{
unsigned long r = (unsigned long)p;
return p == (git_off_t)r;
}
/** @return true if p fits into the range of an int */
GIT_INLINE(int) git__is_int(long long p)
{
int r = (int)p;
return p == (long long)r;
}
/**
* Sets `one + two` into `out`, unless the arithmetic would overflow.
* @return true if the result fits in a `uint64_t`, false on overflow.
*/
GIT_INLINE(bool) git__add_uint64_overflow(uint64_t *out, uint64_t one, uint64_t two)
{
if (UINT64_MAX - one < two)
return true;
*out = one + two;
return false;
}
/* Use clang/gcc compiler intrinsics whenever possible */
#if (SIZE_MAX == UINT_MAX) && __has_builtin(__builtin_uadd_overflow)
# define git__add_sizet_overflow(out, one, two) \
__builtin_uadd_overflow(one, two, out)
# define git__multiply_sizet_overflow(out, one, two)
__builtin_umul_overflow(one, two, out)
#elif (SIZE_MAX == ULONG_MAX) && __has_builtin(__builtin_uaddl_overflow)
# define git__add_sizet_overflow(out, one, two) \
__builtin_uaddl_overflow(one, two, out)
# define git__multiply_sizet_overflow(out, one, two) \
__builtin_umull_overflow(one, two, out)
#else
/**
* Sets `one + two` into `out`, unless the arithmetic would overflow.
* @return true if the result fits in a `size_t`, false on overflow.
*/
GIT_INLINE(bool) git__add_sizet_overflow(size_t *out, size_t one, size_t two)
{
if (SIZE_MAX - one < two)
return true;
*out = one + two;
return false;
}
/**
* Sets `one * two` into `out`, unless the arithmetic would overflow.
* @return true if the result fits in a `size_t`, false on overflow.
*/
GIT_INLINE(bool) git__multiply_sizet_overflow(size_t *out, size_t one, size_t two)
{
if (one && SIZE_MAX / one < two)
return true;
*out = one * two;
return false;
}
#endif
#endif /* INCLUDE_integer_h__ */

View File

@ -336,7 +336,7 @@ static int tree_iterator__push_frame(tree_iterator *ti)
{ {
int error = 0; int error = 0;
tree_iterator_frame *head = ti->head, *tf = NULL; tree_iterator_frame *head = ti->head, *tf = NULL;
size_t i, n_entries = 0; size_t i, n_entries = 0, alloclen;
if (head->current >= head->n_entries || !head->entries[head->current]->tree) if (head->current >= head->n_entries || !head->entries[head->current]->tree)
return GIT_ITEROVER; return GIT_ITEROVER;
@ -344,8 +344,10 @@ static int tree_iterator__push_frame(tree_iterator *ti)
for (i = head->current; i < head->next; ++i) for (i = head->current; i < head->next; ++i)
n_entries += git_tree_entrycount(head->entries[i]->tree); n_entries += git_tree_entrycount(head->entries[i]->tree);
tf = git__calloc(sizeof(tree_iterator_frame) + GITERR_CHECK_ALLOC_MULTIPLY(&alloclen, sizeof(tree_iterator_entry *), n_entries);
n_entries * sizeof(tree_iterator_entry *), 1); GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, sizeof(tree_iterator_frame));
tf = git__calloc(1, alloclen);
GITERR_CHECK_ALLOC(tf); GITERR_CHECK_ALLOC(tf);
tf->n_entries = n_entries; tf->n_entries = n_entries;

View File

@ -46,6 +46,19 @@ int main() {
*/ */
/* /*
2013-05-02 (0.2.8):
* Use quadratic probing. When the capacity is power of 2, stepping function
i*(i+1)/2 guarantees to traverse each bucket. It is better than double
hashing on cache performance and is more robust than linear probing.
In theory, double hashing should be more robust than quadratic probing.
However, my implementation is probably not for large hash tables, because
the second hash function is closely tied to the first hash function,
which reduce the effectiveness of double hashing.
Reference: http://research.cs.vt.edu/AVresearch/hashing/quadratic.php
2011-12-29 (0.2.7): 2011-12-29 (0.2.7):
* Minor code clean up; no actual effect. * Minor code clean up; no actual effect.
@ -110,13 +123,13 @@ int main() {
Generic hash table library. Generic hash table library.
*/ */
#define AC_VERSION_KHASH_H "0.2.6" #define AC_VERSION_KHASH_H "0.2.8"
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <limits.h> #include <limits.h>
/* compipler specific configuration */ /* compiler specific configuration */
#if UINT_MAX == 0xffffffffu #if UINT_MAX == 0xffffffffu
typedef unsigned int khint32_t; typedef unsigned int khint32_t;
@ -130,11 +143,13 @@ typedef unsigned long khint64_t;
typedef unsigned long long khint64_t; typedef unsigned long long khint64_t;
#endif #endif
#ifndef kh_inline
#ifdef _MSC_VER #ifdef _MSC_VER
#define kh_inline __inline #define kh_inline __inline
#else #else
#define kh_inline inline #define kh_inline inline
#endif #endif
#endif /* kh_inline */
typedef khint32_t khint_t; typedef khint32_t khint_t;
typedef khint_t khiter_t; typedef khint_t khiter_t;
@ -147,12 +162,6 @@ typedef khint_t khiter_t;
#define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1))) #define __ac_set_isboth_false(flag, i) (flag[i>>4]&=~(3ul<<((i&0xfU)<<1)))
#define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1)) #define __ac_set_isdel_true(flag, i) (flag[i>>4]|=1ul<<((i&0xfU)<<1))
#ifdef KHASH_LINEAR
#define __ac_inc(k, m) 1
#else
#define __ac_inc(k, m) (((k)>>3 ^ (k)<<3) | 1) & (m)
#endif
#define __ac_fsize(m) ((m) < 16? 1 : (m)>>4) #define __ac_fsize(m) ((m) < 16? 1 : (m)>>4)
#ifndef kroundup32 #ifndef kroundup32
@ -168,6 +177,9 @@ typedef khint_t khiter_t;
#ifndef krealloc #ifndef krealloc
#define krealloc(P,Z) realloc(P,Z) #define krealloc(P,Z) realloc(P,Z)
#endif #endif
#ifndef kreallocarray
#define kreallocarray(P,N,Z) ((SIZE_MAX - N < Z) ? NULL : krealloc(P, (N*Z)))
#endif
#ifndef kfree #ifndef kfree
#define kfree(P) free(P) #define kfree(P) free(P)
#endif #endif
@ -175,7 +187,7 @@ typedef khint_t khiter_t;
static const double __ac_HASH_UPPER = 0.77; static const double __ac_HASH_UPPER = 0.77;
#define __KHASH_TYPE(name, khkey_t, khval_t) \ #define __KHASH_TYPE(name, khkey_t, khval_t) \
typedef struct { \ typedef struct kh_##name##_s { \
khint_t n_buckets, size, n_occupied, upper_bound; \ khint_t n_buckets, size, n_occupied, upper_bound; \
khint32_t *flags; \ khint32_t *flags; \
khkey_t *keys; \ khkey_t *keys; \
@ -213,19 +225,19 @@ static const double __ac_HASH_UPPER = 0.77;
SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \ SCOPE khint_t kh_get_##name(const kh_##name##_t *h, khkey_t key) \
{ \ { \
if (h->n_buckets) { \ if (h->n_buckets) { \
khint_t inc, k, i, last, mask; \ khint_t k, i, last, mask, step = 0; \
mask = h->n_buckets - 1; \ mask = h->n_buckets - 1; \
k = __hash_func(key); i = k & mask; \ k = __hash_func(key); i = k & mask; \
inc = __ac_inc(k, mask); last = i; /* inc==1 for linear probing */ \ last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
i = (i + inc) & mask; \ i = (i + (++step)) & mask; \
if (i == last) return h->n_buckets; \ if (i == last) return h->n_buckets; \
} \ } \
return __ac_iseither(h->flags, i)? h->n_buckets : i; \ return __ac_iseither(h->flags, i)? h->n_buckets : i; \
} else return 0; \ } else return 0; \
} \ } \
SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \ SCOPE int kh_resize_##name(kh_##name##_t *h, khint_t new_n_buckets) \
{ /* This function uses 0.25*n_bucktes bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \ { /* This function uses 0.25*n_buckets bytes of working space instead of [sizeof(key_t+val_t)+.25]*n_buckets. */ \
khint32_t *new_flags = 0; \ khint32_t *new_flags = 0; \
khint_t j = 1; \ khint_t j = 1; \
{ \ { \
@ -233,16 +245,16 @@ static const double __ac_HASH_UPPER = 0.77;
if (new_n_buckets < 4) new_n_buckets = 4; \ if (new_n_buckets < 4) new_n_buckets = 4; \
if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \ if (h->size >= (khint_t)(new_n_buckets * __ac_HASH_UPPER + 0.5)) j = 0; /* requested size is too small */ \
else { /* hash table size to be changed (shrink or expand); rehash */ \ else { /* hash table size to be changed (shrink or expand); rehash */ \
new_flags = (khint32_t*)kmalloc(__ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ new_flags = (khint32_t*)kreallocarray(NULL, __ac_fsize(new_n_buckets), sizeof(khint32_t)); \
if (!new_flags) return -1; \ if (!new_flags) return -1; \
memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \ memset(new_flags, 0xaa, __ac_fsize(new_n_buckets) * sizeof(khint32_t)); \
if (h->n_buckets < new_n_buckets) { /* expand */ \ if (h->n_buckets < new_n_buckets) { /* expand */ \
khkey_t *new_keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ khkey_t *new_keys = (khkey_t*)kreallocarray((void *)h->keys, new_n_buckets, sizeof(khkey_t)); \
if (!new_keys) return -1; \ if (!new_keys) { kfree(new_flags); return -1; } \
h->keys = new_keys; \ h->keys = new_keys; \
if (kh_is_map) { \ if (kh_is_map) { \
khval_t *new_vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ khval_t *new_vals = (khval_t*)kreallocarray((void *)h->vals, new_n_buckets, sizeof(khval_t)); \
if (!new_vals) return -1; \ if (!new_vals) { kfree(new_flags); return -1; } \
h->vals = new_vals; \ h->vals = new_vals; \
} \ } \
} /* otherwise shrink */ \ } /* otherwise shrink */ \
@ -258,11 +270,10 @@ static const double __ac_HASH_UPPER = 0.77;
if (kh_is_map) val = h->vals[j]; \ if (kh_is_map) val = h->vals[j]; \
__ac_set_isdel_true(h->flags, j); \ __ac_set_isdel_true(h->flags, j); \
while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \ while (1) { /* kick-out process; sort of like in Cuckoo hashing */ \
khint_t inc, k, i; \ khint_t k, i, step = 0; \
k = __hash_func(key); \ k = __hash_func(key); \
i = k & new_mask; \ i = k & new_mask; \
inc = __ac_inc(k, new_mask); \ while (!__ac_isempty(new_flags, i)) i = (i + (++step)) & new_mask; \
while (!__ac_isempty(new_flags, i)) i = (i + inc) & new_mask; \
__ac_set_isempty_false(new_flags, i); \ __ac_set_isempty_false(new_flags, i); \
if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \ if (i < h->n_buckets && __ac_iseither(h->flags, i) == 0) { /* kick out the existing element */ \
{ khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \ { khkey_t tmp = h->keys[i]; h->keys[i] = key; key = tmp; } \
@ -277,8 +288,8 @@ static const double __ac_HASH_UPPER = 0.77;
} \ } \
} \ } \
if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \ if (h->n_buckets > new_n_buckets) { /* shrink the hash table */ \
h->keys = (khkey_t*)krealloc((void *)h->keys, new_n_buckets * sizeof(khkey_t)); \ h->keys = (khkey_t*)kreallocarray((void *)h->keys, new_n_buckets, sizeof(khkey_t)); \
if (kh_is_map) h->vals = (khval_t*)krealloc((void *)h->vals, new_n_buckets * sizeof(khval_t)); \ if (kh_is_map) h->vals = (khval_t*)kreallocarray((void *)h->vals, new_n_buckets, sizeof(khval_t)); \
} \ } \
kfree(h->flags); /* free the working space */ \ kfree(h->flags); /* free the working space */ \
h->flags = new_flags; \ h->flags = new_flags; \
@ -301,14 +312,14 @@ static const double __ac_HASH_UPPER = 0.77;
} \ } \
} /* TODO: to implement automatically shrinking; resize() already support shrinking */ \ } /* TODO: to implement automatically shrinking; resize() already support shrinking */ \
{ \ { \
khint_t inc, k, i, site, last, mask = h->n_buckets - 1; \ khint_t k, i, site, last, mask = h->n_buckets - 1, step = 0; \
x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \ x = site = h->n_buckets; k = __hash_func(key); i = k & mask; \
if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \ if (__ac_isempty(h->flags, i)) x = i; /* for speed up */ \
else { \ else { \
inc = __ac_inc(k, mask); last = i; \ last = i; \
while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \ while (!__ac_isempty(h->flags, i) && (__ac_isdel(h->flags, i) || !__hash_equal(h->keys[i], key))) { \
if (__ac_isdel(h->flags, i)) site = i; \ if (__ac_isdel(h->flags, i)) site = i; \
i = (i + inc) & mask; \ i = (i + (++step)) & mask; \
if (i == last) { x = site; break; } \ if (i == last) { x = site; break; } \
} \ } \
if (x == h->n_buckets) { \ if (x == h->n_buckets) { \
@ -449,7 +460,8 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
@param name Name of the hash table [symbol] @param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*] @param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys] @param k Key [type of keys]
@param r Extra return code: 0 if the key is present in the hash table; @param r Extra return code: -1 if the operation failed;
0 if the key is present in the hash table;
1 if the bucket is empty (never used); 2 if the element in 1 if the bucket is empty (never used); 2 if the element in
the bucket has been deleted [int*] the bucket has been deleted [int*]
@return Iterator to the inserted element [khint_t] @return Iterator to the inserted element [khint_t]
@ -461,7 +473,7 @@ static kh_inline khint_t __ac_Wang_hash(khint_t key)
@param name Name of the hash table [symbol] @param name Name of the hash table [symbol]
@param h Pointer to the hash table [khash_t(name)*] @param h Pointer to the hash table [khash_t(name)*]
@param k Key [type of keys] @param k Key [type of keys]
@return Iterator to the found element, or kh_end(h) is the element is absent [khint_t] @return Iterator to the found element, or kh_end(h) if the element is absent [khint_t]
*/ */
#define kh_get(name, h, k) kh_get_##name(h, k) #define kh_get(name, h, k) kh_get_##name(h, k)

View File

@ -1169,7 +1169,7 @@ int git_merge_diff_list__find_renames(
goto done; goto done;
if (diff_list->conflicts.length <= opts->target_limit) { if (diff_list->conflicts.length <= opts->target_limit) {
cache_size = diff_list->conflicts.length * 3; GITERR_CHECK_ALLOC_MULTIPLY(&cache_size, diff_list->conflicts.length, 3);
cache = git__calloc(cache_size, sizeof(void *)); cache = git__calloc(cache_size, sizeof(void *));
GITERR_CHECK_ALLOC(cache); GITERR_CHECK_ALLOC(cache);
@ -2223,12 +2223,13 @@ static int merge_ancestor_head(
size_t their_heads_len) size_t their_heads_len)
{ {
git_oid *oids, ancestor_oid; git_oid *oids, ancestor_oid;
size_t i; size_t i, alloc_len;
int error = 0; int error = 0;
assert(repo && our_head && their_heads); assert(repo && our_head && their_heads);
oids = git__calloc(their_heads_len + 1, sizeof(git_oid)); GITERR_CHECK_ALLOC_ADD(&alloc_len, their_heads_len, 1);
oids = git__calloc(alloc_len, sizeof(git_oid));
GITERR_CHECK_ALLOC(oids); GITERR_CHECK_ALLOC(oids);
git_oid_cpy(&oids[0], git_commit_id(our_head->commit)); git_oid_cpy(&oids[0], git_commit_id(our_head->commit));

View File

@ -314,7 +314,7 @@ static int note_new(
{ {
git_note *note = NULL; git_note *note = NULL;
note = (git_note *)git__malloc(sizeof(git_note)); note = git__malloc(sizeof(git_note));
GITERR_CHECK_ALLOC(note); GITERR_CHECK_ALLOC(note);
git_oid_cpy(&note->id, note_oid); git_oid_cpy(&note->id, note_oid);

View File

@ -216,41 +216,43 @@ int git_odb__hashfd_filtered(
int git_odb__hashlink(git_oid *out, const char *path) int git_odb__hashlink(git_oid *out, const char *path)
{ {
struct stat st; struct stat st;
git_off_t size; int size;
int result; int result;
if (git_path_lstat(path, &st) < 0) if (git_path_lstat(path, &st) < 0)
return -1; return -1;
size = st.st_size; if (!git__is_int(st.st_size) || (int)st.st_size < 0) {
giterr_set(GITERR_FILESYSTEM, "File size overflow for 32-bit systems");
if (!git__is_sizet(size)) {
giterr_set(GITERR_OS, "File size overflow for 32-bit systems");
return -1; return -1;
} }
size = (int)st.st_size;
if (S_ISLNK(st.st_mode)) { if (S_ISLNK(st.st_mode)) {
char *link_data; char *link_data;
ssize_t read_len; int read_len;
size_t alloc_size;
link_data = git__malloc((size_t)(size + 1)); GITERR_CHECK_ALLOC_ADD(&alloc_size, size, 1);
link_data = git__malloc(alloc_size);
GITERR_CHECK_ALLOC(link_data); GITERR_CHECK_ALLOC(link_data);
read_len = p_readlink(path, link_data, (size_t)size); read_len = p_readlink(path, link_data, size);
link_data[size] = '\0'; link_data[size] = '\0';
if (read_len != (ssize_t)size) { if (read_len != size) {
giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path); giterr_set(GITERR_OS, "Failed to read symlink data for '%s'", path);
git__free(link_data); git__free(link_data);
return -1; return -1;
} }
result = git_odb_hash(out, link_data, (size_t)size, GIT_OBJ_BLOB); result = git_odb_hash(out, link_data, size, GIT_OBJ_BLOB);
git__free(link_data); git__free(link_data);
} else { } else {
int fd = git_futils_open_ro(path); int fd = git_futils_open_ro(path);
if (fd < 0) if (fd < 0)
return -1; return -1;
result = git_odb__hashfd(out, fd, (size_t)size, GIT_OBJ_BLOB); result = git_odb__hashfd(out, fd, size, GIT_OBJ_BLOB);
p_close(fd); p_close(fd);
} }

View File

@ -63,8 +63,12 @@ typedef struct {
static int object_file_name( static int object_file_name(
git_buf *name, const loose_backend *be, const git_oid *id) git_buf *name, const loose_backend *be, const git_oid *id)
{ {
size_t alloclen;
/* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */ /* expand length for object root + 40 hex sha1 chars + 2 * '/' + '\0' */
if (git_buf_grow(name, be->objects_dirlen + GIT_OID_HEXSZ + 3) < 0) GITERR_CHECK_ALLOC_ADD(&alloclen, be->objects_dirlen, GIT_OID_HEXSZ);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 3);
if (git_buf_grow(name, alloclen) < 0)
return -1; return -1;
git_buf_set(name, be->objects_dir, be->objects_dirlen); git_buf_set(name, be->objects_dir, be->objects_dirlen);
@ -261,14 +265,15 @@ static int inflate_buffer(void *in, size_t inlen, void *out, size_t outlen)
static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr) static void *inflate_tail(z_stream *s, void *hb, size_t used, obj_hdr *hdr)
{ {
unsigned char *buf, *head = hb; unsigned char *buf, *head = hb;
size_t tail; size_t tail, alloc_size;
/* /*
* allocate a buffer to hold the inflated data and copy the * allocate a buffer to hold the inflated data and copy the
* initial sequence of inflated data from the tail of the * initial sequence of inflated data from the tail of the
* head buffer, if any. * head buffer, if any.
*/ */
if ((buf = git__malloc(hdr->size + 1)) == NULL) { if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, hdr->size, 1) ||
(buf = git__malloc(alloc_size)) == NULL) {
inflateEnd(s); inflateEnd(s);
return NULL; return NULL;
} }
@ -306,7 +311,7 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
{ {
unsigned char *in, *buf; unsigned char *in, *buf;
obj_hdr hdr; obj_hdr hdr;
size_t len, used; size_t len, used, alloclen;
/* /*
* read the object header, which is an (uncompressed) * read the object header, which is an (uncompressed)
@ -321,7 +326,8 @@ static int inflate_packlike_loose_disk_obj(git_rawobj *out, git_buf *obj)
/* /*
* allocate a buffer and inflate the data into it * allocate a buffer and inflate the data into it
*/ */
buf = git__malloc(hdr.size + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, hdr.size, 1);
buf = git__malloc(alloclen);
GITERR_CHECK_ALLOC(buf); GITERR_CHECK_ALLOC(buf);
in = ((unsigned char *)obj->ptr) + used; in = ((unsigned char *)obj->ptr) + used;
@ -515,12 +521,14 @@ static int locate_object_short_oid(
size_t len) size_t len)
{ {
char *objects_dir = backend->objects_dir; char *objects_dir = backend->objects_dir;
size_t dir_len = strlen(objects_dir); size_t dir_len = strlen(objects_dir), alloc_len;
loose_locate_object_state state; loose_locate_object_state state;
int error; int error;
/* prealloc memory for OBJ_DIR/xx/xx..38x..xx */ /* prealloc memory for OBJ_DIR/xx/xx..38x..xx */
if (git_buf_grow(object_location, dir_len + 3 + GIT_OID_HEXSZ) < 0) GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 3);
if (git_buf_grow(object_location, alloc_len) < 0)
return -1; return -1;
git_buf_set(object_location, objects_dir, dir_len); git_buf_set(object_location, objects_dir, dir_len);
@ -563,9 +571,11 @@ static int locate_object_short_oid(
return error; return error;
/* Update the location according to the oid obtained */ /* Update the location according to the oid obtained */
GITERR_CHECK_ALLOC_ADD(&alloc_len, dir_len, GIT_OID_HEXSZ);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
git_buf_truncate(object_location, dir_len); git_buf_truncate(object_location, dir_len);
if (git_buf_grow(object_location, dir_len + GIT_OID_HEXSZ + 2) < 0) if (git_buf_grow(object_location, alloc_len) < 0)
return -1; return -1;
git_oid_pathfmt(object_location->ptr + dir_len, res_oid); git_oid_pathfmt(object_location->ptr + dir_len, res_oid);
@ -922,13 +932,15 @@ int git_odb_backend_loose(
unsigned int file_mode) unsigned int file_mode)
{ {
loose_backend *backend; loose_backend *backend;
size_t objects_dirlen; size_t objects_dirlen, alloclen;
assert(backend_out && objects_dir); assert(backend_out && objects_dir);
objects_dirlen = strlen(objects_dir); objects_dirlen = strlen(objects_dir);
backend = git__calloc(1, sizeof(loose_backend) + objects_dirlen + 2); GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(loose_backend), objects_dirlen);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 2);
backend = git__calloc(1, alloclen);
GITERR_CHECK_ALLOC(backend); GITERR_CHECK_ALLOC(backend);
backend->parent.version = GIT_ODB_BACKEND_VERSION; backend->parent.version = GIT_ODB_BACKEND_VERSION;

View File

@ -38,6 +38,7 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void
struct memory_packer_db *db = (struct memory_packer_db *)_backend; struct memory_packer_db *db = (struct memory_packer_db *)_backend;
struct memobject *obj = NULL; struct memobject *obj = NULL;
khiter_t pos; khiter_t pos;
size_t alloc_len;
int rval; int rval;
pos = kh_put(oid, db->objects, oid, &rval); pos = kh_put(oid, db->objects, oid, &rval);
@ -47,7 +48,8 @@ static int impl__write(git_odb_backend *_backend, const git_oid *oid, const void
if (rval == 0) if (rval == 0)
return 0; return 0;
obj = git__malloc(sizeof(struct memobject) + len); GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(struct memobject), len);
obj = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(obj); GITERR_CHECK_ALLOC(obj);
memcpy(obj->data, data, len); memcpy(obj->data, data, len);

View File

@ -13,6 +13,7 @@
#define kmalloc git__malloc #define kmalloc git__malloc
#define kcalloc git__calloc #define kcalloc git__calloc
#define krealloc git__realloc #define krealloc git__realloc
#define kreallocarray git__reallocarray
#define kfree git__free #define kfree git__free
#include "khash.h" #include "khash.h"

View File

@ -261,7 +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)
{ {
self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node)); self->nodes = git__reallocarray(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) {

View File

@ -13,6 +13,7 @@
#define kmalloc git__malloc #define kmalloc git__malloc
#define kcalloc git__calloc #define kcalloc git__calloc
#define krealloc git__realloc #define krealloc git__realloc
#define kreallocarray git__reallocarray
#define kfree git__free #define kfree git__free
#include "khash.h" #include "khash.h"

View File

@ -190,6 +190,7 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
{ {
git_pobject *po; git_pobject *po;
khiter_t pos; khiter_t pos;
size_t newsize;
int ret; int ret;
assert(pb && oid); assert(pb && oid);
@ -201,9 +202,18 @@ int git_packbuilder_insert(git_packbuilder *pb, const git_oid *oid,
return 0; return 0;
if (pb->nr_objects >= pb->nr_alloc) { if (pb->nr_objects >= pb->nr_alloc) {
pb->nr_alloc = (pb->nr_alloc + 1024) * 3 / 2; GITERR_CHECK_ALLOC_ADD(&newsize, pb->nr_alloc, 1024);
pb->object_list = git__realloc(pb->object_list, GITERR_CHECK_ALLOC_MULTIPLY(&newsize, newsize, 3 / 2);
pb->nr_alloc * sizeof(*po));
if (!git__is_uint32(newsize)) {
giterr_set(GITERR_NOMEMORY, "Packfile too large to fit in memory.");
return -1;
}
pb->nr_alloc = (uint32_t)newsize;
pb->object_list = git__reallocarray(pb->object_list,
pb->nr_alloc, sizeof(*po));
GITERR_CHECK_ALLOC(pb->object_list); GITERR_CHECK_ALLOC(pb->object_list);
rehash(pb); rehash(pb);
} }
@ -499,8 +509,10 @@ static int cb_tag_foreach(const char *name, git_oid *oid, void *data)
static git_pobject **compute_write_order(git_packbuilder *pb) 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 = git__malloc(sizeof(*wo) * pb->nr_objects); if ((wo = git__mallocarray(pb->nr_objects, sizeof(*wo))) == NULL)
return NULL;
for (i = 0; i < pb->nr_objects; i++) { for (i = 0; i < pb->nr_objects; i++) {
git_pobject *po = pb->object_list + i; git_pobject *po = pb->object_list + i;
@ -770,10 +782,13 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
*mem_usage += sz; *mem_usage += sz;
} }
if (!src->data) { if (!src->data) {
if (git_odb_read(&obj, pb->odb, &src_object->id) < 0) size_t obj_sz;
if (git_odb_read(&obj, pb->odb, &src_object->id) < 0 ||
!git__is_ulong(obj_sz = git_odb_object_size(obj)))
return -1; return -1;
sz = (unsigned long)git_odb_object_size(obj); sz = (unsigned long)obj_sz;
src->data = git__malloc(sz); src->data = git__malloc(sz);
GITERR_CHECK_ALLOC(src->data); GITERR_CHECK_ALLOC(src->data);
memcpy(src->data, git_odb_object_data(obj), sz); memcpy(src->data, git_odb_object_data(obj), sz);
@ -817,11 +832,14 @@ static int try_delta(git_packbuilder *pb, struct unpacked *trg,
trg_object->delta_data = NULL; trg_object->delta_data = NULL;
} }
if (delta_cacheable(pb, src_size, trg_size, delta_size)) { if (delta_cacheable(pb, src_size, trg_size, delta_size)) {
pb->delta_cache_size += delta_size; bool overflow = git__add_uint64_overflow(
&pb->delta_cache_size, pb->delta_cache_size, delta_size);
git_packbuilder__cache_unlock(pb); git_packbuilder__cache_unlock(pb);
trg_object->delta_data = git__realloc(delta_buf, delta_size); if (overflow ||
GITERR_CHECK_ALLOC(trg_object->delta_data); !(trg_object->delta_data = git__realloc(delta_buf, delta_size)))
return -1;
} else { } else {
/* create delta when writing the pack */ /* create delta when writing the pack */
git_packbuilder__cache_unlock(pb); git_packbuilder__cache_unlock(pb);
@ -1088,7 +1106,7 @@ static int ll_find_deltas(git_packbuilder *pb, git_pobject **list,
return 0; return 0;
} }
p = git__malloc(pb->nr_threads * sizeof(*p)); p = git__mallocarray(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 */
@ -1239,7 +1257,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);
delta_list = git__malloc(pb->nr_objects * sizeof(*delta_list)); delta_list = git__mallocarray(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) {

View File

@ -624,7 +624,7 @@ int git_packfile_unpack(
struct pack_chain_elem *elem = NULL, *stack; struct pack_chain_elem *elem = NULL, *stack;
git_pack_cache_entry *cached = NULL; git_pack_cache_entry *cached = NULL;
struct pack_chain_elem small_stack[SMALL_STACK_SIZE]; struct pack_chain_elem small_stack[SMALL_STACK_SIZE];
size_t stack_size = 0, elem_pos; size_t stack_size = 0, elem_pos, alloclen;
git_otype base_type; git_otype base_type;
/* /*
@ -683,8 +683,11 @@ int git_packfile_unpack(
*/ */
if (cached && stack_size == 1) { if (cached && stack_size == 1) {
void *data = obj->data; void *data = obj->data;
obj->data = git__malloc(obj->len + 1);
GITERR_CHECK_ALLOC_ADD(&alloclen, obj->len, 1);
obj->data = git__malloc(alloclen);
GITERR_CHECK_ALLOC(obj->data); GITERR_CHECK_ALLOC(obj->data);
memcpy(obj->data, data, obj->len + 1); memcpy(obj->data, data, obj->len + 1);
git_atomic_dec(&cached->refcount); git_atomic_dec(&cached->refcount);
goto cleanup; goto cleanup;
@ -837,16 +840,18 @@ int packfile_unpack_compressed(
size_t size, size_t size,
git_otype type) git_otype type)
{ {
size_t buf_size;
int st; int st;
z_stream stream; z_stream stream;
unsigned char *buffer, *in; unsigned char *buffer, *in;
buffer = git__calloc(1, size + 1); GITERR_CHECK_ALLOC_ADD(&buf_size, size, 1);
buffer = git__calloc(1, buf_size);
GITERR_CHECK_ALLOC(buffer); GITERR_CHECK_ALLOC(buffer);
memset(&stream, 0, sizeof(stream)); memset(&stream, 0, sizeof(stream));
stream.next_out = buffer; stream.next_out = buffer;
stream.avail_out = (uInt)size + 1; stream.avail_out = (uInt)buf_size;
stream.zalloc = use_git_alloc; stream.zalloc = use_git_alloc;
stream.zfree = use_git_free; stream.zfree = use_git_free;
@ -1085,14 +1090,17 @@ int git_packfile_alloc(struct git_pack_file **pack_out, const char *path)
{ {
struct stat st; struct stat st;
struct git_pack_file *p; struct git_pack_file *p;
size_t path_len = path ? strlen(path) : 0; size_t path_len = path ? strlen(path) : 0, alloc_len;
*pack_out = NULL; *pack_out = NULL;
if (path_len < strlen(".idx")) if (path_len < strlen(".idx"))
return git_odb__error_notfound("invalid packfile path", NULL); return git_odb__error_notfound("invalid packfile path", NULL);
p = git__calloc(1, sizeof(*p) + path_len + 2); GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(*p), path_len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 2);
p = git__calloc(1, alloc_len);
GITERR_CHECK_ALLOC(p); GITERR_CHECK_ALLOC(p);
memcpy(p->pack_name, path, path_len + 1); memcpy(p->pack_name, path, path_len + 1);

View File

@ -620,9 +620,12 @@ static bool _check_dir_contents(
bool result; bool result;
size_t dir_size = git_buf_len(dir); size_t dir_size = git_buf_len(dir);
size_t sub_size = strlen(sub); size_t sub_size = strlen(sub);
size_t alloc_size;
/* leave base valid even if we could not make space for subdir */ /* leave base valid even if we could not make space for subdir */
if (git_buf_try_grow(dir, dir_size + sub_size + 2, false, false) < 0) if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, dir_size, sub_size) ||
GIT_ADD_SIZET_OVERFLOW(&alloc_size, alloc_size, 2) ||
git_buf_try_grow(dir, alloc_size, false, false) < 0)
return false; return false;
/* save excursion */ /* save excursion */
@ -784,7 +787,7 @@ int git_path_cmp(
int git_path_make_relative(git_buf *path, const char *parent) int git_path_make_relative(git_buf *path, const char *parent)
{ {
const char *p, *q, *p_dirsep, *q_dirsep; const char *p, *q, *p_dirsep, *q_dirsep;
size_t plen = path->size, newlen, depth = 1, i, offset; size_t plen = path->size, newlen, alloclen, depth = 1, i, offset;
for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) { for (p_dirsep = p = path->ptr, q_dirsep = q = parent; *p && *q; p++, q++) {
if (*p == '/' && *q == '/') { if (*p == '/' && *q == '/') {
@ -822,11 +825,14 @@ int git_path_make_relative(git_buf *path, const char *parent)
for (; (q = strchr(q, '/')) && *(q + 1); q++) for (; (q = strchr(q, '/')) && *(q + 1); q++)
depth++; depth++;
newlen = (depth * 3) + plen; GITERR_CHECK_ALLOC_MULTIPLY(&newlen, depth, 3);
GITERR_CHECK_ALLOC_ADD(&newlen, newlen, plen);
GITERR_CHECK_ALLOC_ADD(&alloclen, newlen, 1);
/* save the offset as we might realllocate the pointer */ /* save the offset as we might realllocate the pointer */
offset = p - path->ptr; offset = p - path->ptr;
if (git_buf_try_grow(path, newlen + 1, 1, 0) < 0) if (git_buf_try_grow(path, alloclen, 1, 0) < 0)
return -1; return -1;
p = path->ptr + offset; p = path->ptr + offset;
@ -871,7 +877,7 @@ void git_path_iconv_clear(git_path_iconv_t *ic)
int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen) int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen)
{ {
char *nfd = *in, *nfc; char *nfd = *in, *nfc;
size_t nfdlen = *inlen, nfclen, wantlen = nfdlen, rv; size_t nfdlen = *inlen, nfclen, wantlen = nfdlen, alloclen, rv;
int retry = 1; int retry = 1;
if (!ic || ic->map == (iconv_t)-1 || if (!ic || ic->map == (iconv_t)-1 ||
@ -881,7 +887,8 @@ int git_path_iconv(git_path_iconv_t *ic, char **in, size_t *inlen)
git_buf_clear(&ic->buf); git_buf_clear(&ic->buf);
while (1) { while (1) {
if (git_buf_grow(&ic->buf, wantlen + 1) < 0) GITERR_CHECK_ALLOC_ADD(&alloclen, wantlen, 1);
if (git_buf_grow(&ic->buf, alloclen) < 0)
return -1; return -1;
nfc = ic->buf.ptr + ic->buf.size; nfc = ic->buf.ptr + ic->buf.size;
@ -1057,6 +1064,37 @@ int git_path_direach(
return error; return error;
} }
static int entry_path_alloc(
char **out,
const char *path,
size_t path_len,
const char *de_path,
size_t de_len,
size_t alloc_extra)
{
int need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
size_t alloc_size;
char *entry_path;
GITERR_CHECK_ALLOC_ADD(&alloc_size, path_len, de_len);
GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, need_slash);
GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, 1);
GITERR_CHECK_ALLOC_ADD(&alloc_size, alloc_size, alloc_extra);
entry_path = git__calloc(1, alloc_size);
GITERR_CHECK_ALLOC(entry_path);
if (path_len)
memcpy(entry_path, path, path_len);
if (need_slash)
entry_path[path_len] = '/';
memcpy(&entry_path[path_len + need_slash], de_path, de_len);
*out = entry_path;
return 0;
}
int git_path_dirload( int git_path_dirload(
const char *path, const char *path,
size_t prefix_len, size_t prefix_len,
@ -1064,7 +1102,7 @@ int git_path_dirload(
unsigned int flags, unsigned int flags,
git_vector *contents) git_vector *contents)
{ {
int error, need_slash; int error;
DIR *dir; DIR *dir;
size_t path_len; size_t path_len;
path_dirent_data de_data; path_dirent_data de_data;
@ -1096,11 +1134,10 @@ int git_path_dirload(
path += prefix_len; path += prefix_len;
path_len -= prefix_len; path_len -= prefix_len;
need_slash = (path_len > 0 && path[path_len-1] != '/') ? 1 : 0;
while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) { while ((error = p_readdir_r(dir, de_buf, &de)) == 0 && de != NULL) {
char *entry_path, *de_path = de->d_name; char *entry_path, *de_path = de->d_name;
size_t alloc_size, de_len = strlen(de_path); size_t de_len = strlen(de_path);
if (git_path_is_dot_or_dotdot(de_path)) if (git_path_is_dot_or_dotdot(de_path))
continue; continue;
@ -1110,17 +1147,9 @@ int git_path_dirload(
break; break;
#endif #endif
alloc_size = path_len + need_slash + de_len + 1 + alloc_extra; if ((error = entry_path_alloc(&entry_path,
if ((entry_path = git__calloc(alloc_size, 1)) == NULL) { path, path_len, de_path, de_len, alloc_extra)) < 0)
error = -1;
break; break;
}
if (path_len)
memcpy(entry_path, path, path_len);
if (need_slash)
entry_path[path_len] = '/';
memcpy(&entry_path[path_len + need_slash], de_path, de_len);
if ((error = git_vector_insert(contents, entry_path)) < 0) { if ((error = git_vector_insert(contents, entry_path)) < 0) {
git__free(entry_path); git__free(entry_path);

View File

@ -107,21 +107,22 @@ static void pool_insert_page(git_pool *pool, git_pool_page *page)
static void *pool_alloc_page(git_pool *pool, uint32_t size) static void *pool_alloc_page(git_pool *pool, uint32_t size)
{ {
git_pool_page *page; git_pool_page *page;
uint32_t alloc_size; uint32_t new_page_size;
size_t alloc_size;
if (size <= pool->page_size) if (size <= pool->page_size)
alloc_size = pool->page_size; new_page_size = pool->page_size;
else { else {
alloc_size = size; new_page_size = size;
pool->has_large_page_alloc = 1; pool->has_large_page_alloc = 1;
} }
page = git__calloc(1, alloc_size + sizeof(git_pool_page)); if (GIT_ADD_SIZET_OVERFLOW(&alloc_size, new_page_size, sizeof(git_pool_page)) ||
if (!page) !(page = git__calloc(1, alloc_size)))
return NULL; return NULL;
page->size = alloc_size; page->size = new_page_size;
page->avail = alloc_size - size; page->avail = new_page_size - size;
if (page->avail > 0) if (page->avail > 0)
pool_insert_page(pool, page); pool_insert_page(pool, page);

View File

@ -155,6 +155,14 @@ ssize_t p_read(git_file fd, void *buf, size_t cnt)
{ {
char *b = buf; char *b = buf;
if (!git__is_ssizet(cnt)) {
#ifdef GIT_WIN32
SetLastError(ERROR_INVALID_PARAMETER);
#endif
errno = EINVAL;
return -1;
}
while (cnt) { while (cnt) {
ssize_t r; ssize_t r;
#ifdef GIT_WIN32 #ifdef GIT_WIN32
@ -229,7 +237,9 @@ int p_mmap(git_map *out, size_t len, int prot, int flags, int fd, git_off_t offs
out->data = malloc(len); out->data = malloc(len);
GITERR_CHECK_ALLOC(out->data); GITERR_CHECK_ALLOC(out->data);
if ((p_lseek(fd, offset, SEEK_SET) < 0) || ((size_t)p_read(fd, out->data, len) != len)) { if (!git__is_ssizet(len) ||
(p_lseek(fd, offset, SEEK_SET) < 0) ||
(p_read(fd, out->data, len) != (ssize_t)len)) {
giterr_set(GITERR_OS, "mmap emulation failed"); giterr_set(GITERR_OS, "mmap emulation failed");
return -1; return -1;
} }

View File

@ -36,12 +36,12 @@ enum {
static git_reference *alloc_ref(const char *name) static git_reference *alloc_ref(const char *name)
{ {
git_reference *ref; git_reference *ref = NULL;
size_t namelen = strlen(name); size_t namelen = strlen(name), reflen;
if ((ref = git__calloc(1, sizeof(git_reference) + namelen + 1)) == NULL)
return NULL;
if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
!GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
(ref = git__calloc(1, reflen)) != NULL)
memcpy(ref->name, name, namelen + 1); memcpy(ref->name, name, namelen + 1);
return ref; return ref;
@ -94,10 +94,14 @@ git_reference *git_reference__set_name(
git_reference *ref, const char *name) git_reference *ref, const char *name)
{ {
size_t namelen = strlen(name); size_t namelen = strlen(name);
git_reference *rewrite = size_t reflen;
git__realloc(ref, sizeof(git_reference) + namelen + 1); git_reference *rewrite = NULL;
if (rewrite != NULL)
if (!GIT_ADD_SIZET_OVERFLOW(&reflen, sizeof(git_reference), namelen) &&
!GIT_ADD_SIZET_OVERFLOW(&reflen, reflen, 1) &&
(rewrite = git__realloc(ref, reflen)) != NULL)
memcpy(rewrite->name, name, namelen + 1); memcpy(rewrite->name, name, namelen + 1);
return rewrite; return rewrite;
} }

View File

@ -383,10 +383,9 @@ int git_remote_lookup(git_remote **out, git_repository *repo, const char *name)
if ((error = git_repository_config_snapshot(&config, repo)) < 0) if ((error = git_repository_config_snapshot(&config, repo)) < 0)
return error; return error;
remote = git__malloc(sizeof(git_remote)); remote = git__calloc(1, sizeof(git_remote));
GITERR_CHECK_ALLOC(remote); GITERR_CHECK_ALLOC(remote);
memset(remote, 0x0, sizeof(git_remote));
remote->update_fetchhead = 1; remote->update_fetchhead = 1;
remote->name = git__strdup(name); remote->name = git__strdup(name);
GITERR_CHECK_ALLOC(remote->name); GITERR_CHECK_ALLOC(remote->name);

View File

@ -503,13 +503,9 @@ static int prepare_walk(git_revwalk *walk)
int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo) int git_revwalk_new(git_revwalk **revwalk_out, git_repository *repo)
{ {
git_revwalk *walk; git_revwalk *walk = git__calloc(1, sizeof(git_revwalk));
walk = git__malloc(sizeof(git_revwalk));
GITERR_CHECK_ALLOC(walk); GITERR_CHECK_ALLOC(walk);
memset(walk, 0x0, sizeof(git_revwalk));
walk->commits = git_oidmap_alloc(); walk->commits = git_oidmap_alloc();
GITERR_CHECK_ALLOC(walk->commits); GITERR_CHECK_ALLOC(walk->commits);

View File

@ -11,11 +11,13 @@ int git_sortedcache_new(
const char *path) const char *path)
{ {
git_sortedcache *sc; git_sortedcache *sc;
size_t pathlen; size_t pathlen, alloclen;
pathlen = path ? strlen(path) : 0; pathlen = path ? strlen(path) : 0;
sc = git__calloc(sizeof(git_sortedcache) + pathlen + 1, 1); GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_sortedcache), pathlen);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
sc = git__calloc(1, alloclen);
GITERR_CHECK_ALLOC(sc); GITERR_CHECK_ALLOC(sc);
if (git_pool_init(&sc->pool, 1, 0) < 0 || if (git_pool_init(&sc->pool, 1, 0) < 0 ||

View File

@ -12,6 +12,7 @@
#define kmalloc git__malloc #define kmalloc git__malloc
#define kcalloc git__calloc #define kcalloc git__calloc
#define krealloc git__realloc #define krealloc git__realloc
#define kreallocarray git__reallocarray
#define kfree git__free #define kfree git__free
#include "khash.h" #include "khash.h"

View File

@ -72,7 +72,7 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
}; };
unsigned int i; unsigned int i;
size_t text_len; size_t text_len, alloc_len;
char *search; char *search;
if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0) if (git_oid__parse(&tag->target, &buffer, buffer_end, "object ") < 0)
@ -117,7 +117,8 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
text_len = search - buffer; text_len = search - buffer;
tag->tag_name = git__malloc(text_len + 1); GITERR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1);
tag->tag_name = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(tag->tag_name); GITERR_CHECK_ALLOC(tag->tag_name);
memcpy(tag->tag_name, buffer, text_len); memcpy(tag->tag_name, buffer, text_len);
@ -141,7 +142,8 @@ static int tag_parse(git_tag *tag, const char *buffer, const char *buffer_end)
text_len = buffer_end - ++buffer; text_len = buffer_end - ++buffer;
tag->message = git__malloc(text_len + 1); GITERR_CHECK_ALLOC_ADD(&alloc_len, text_len, 1);
tag->message = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(tag->message); GITERR_CHECK_ALLOC(tag->message);
memcpy(tag->message, buffer, text_len); memcpy(tag->message, buffer, text_len);

View File

@ -306,12 +306,15 @@ int git_cred_default_new(git_cred **cred)
int git_cred_username_new(git_cred **cred, const char *username) int git_cred_username_new(git_cred **cred, const char *username)
{ {
git_cred_username *c; git_cred_username *c;
size_t len; size_t len, allocsize;
assert(cred); assert(cred);
len = strlen(username); len = strlen(username);
c = git__malloc(sizeof(git_cred_username) + len + 1);
GITERR_CHECK_ALLOC_ADD(&allocsize, sizeof(git_cred_username), len);
GITERR_CHECK_ALLOC_ADD(&allocsize, allocsize, 1);
c = git__malloc(allocsize);
GITERR_CHECK_ALLOC(c); GITERR_CHECK_ALLOC(c);
c->parent.credtype = GIT_CREDTYPE_USERNAME; c->parent.credtype = GIT_CREDTYPE_USERNAME;

View File

@ -154,7 +154,7 @@ static int git_proto_stream_alloc(
if (!stream) if (!stream)
return -1; return -1;
s = git__calloc(sizeof(git_proto_stream), 1); s = git__calloc(1, sizeof(git_proto_stream));
GITERR_CHECK_ALLOC(s); GITERR_CHECK_ALLOC(s);
s->parent.subtransport = &t->parent; s->parent.subtransport = &t->parent;
@ -347,7 +347,7 @@ int git_smart_subtransport_git(git_smart_subtransport **out, git_transport *owne
if (!out) if (!out)
return -1; return -1;
t = git__calloc(sizeof(git_subtransport), 1); t = git__calloc(1, sizeof(git_subtransport));
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->owner = owner; t->owner = owner;

View File

@ -420,7 +420,7 @@ static int local_push(
const git_error *last; const git_error *last;
char *ref = spec->refspec.dst; char *ref = spec->refspec.dst;
status = git__calloc(sizeof(push_status), 1); status = git__calloc(1, sizeof(push_status));
if (!status) if (!status)
goto on_error; goto on_error;

View File

@ -380,7 +380,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
if (!param) if (!param)
return -1; return -1;
t = git__calloc(sizeof(transport_smart), 1); t = git__calloc(1, sizeof(transport_smart));
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->parent.version = GIT_TRANSPORT_VERSION; t->parent.version = GIT_TRANSPORT_VERSION;

View File

@ -102,8 +102,11 @@ static int pack_pkt(git_pkt **out)
static int comment_pkt(git_pkt **out, const char *line, size_t len) static int comment_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_comment *pkt; git_pkt_comment *pkt;
size_t alloclen;
pkt = git__malloc(sizeof(git_pkt_comment) + len + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_comment), len);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
pkt = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_COMMENT; pkt->type = GIT_PKT_COMMENT;
@ -118,11 +121,15 @@ static int comment_pkt(git_pkt **out, const char *line, size_t len)
static int err_pkt(git_pkt **out, const char *line, size_t len) static int err_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_err *pkt; git_pkt_err *pkt;
size_t alloclen;
/* Remove "ERR " from the line */ /* Remove "ERR " from the line */
line += 4; line += 4;
len -= 4; len -= 4;
pkt = git__malloc(sizeof(git_pkt_err) + len + 1);
GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len);
GITERR_CHECK_ALLOC_ADD(&alloclen, alloclen, 1);
pkt = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_ERR; pkt->type = GIT_PKT_ERR;
@ -138,10 +145,13 @@ static int err_pkt(git_pkt **out, const char *line, size_t len)
static int data_pkt(git_pkt **out, const char *line, size_t len) static int data_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_data *pkt; git_pkt_data *pkt;
size_t alloclen;
line++; line++;
len--; len--;
pkt = git__malloc(sizeof(git_pkt_data) + len);
GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len);
pkt = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_DATA; pkt->type = GIT_PKT_DATA;
@ -156,10 +166,13 @@ static int data_pkt(git_pkt **out, const char *line, size_t len)
static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len) static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_progress *pkt; git_pkt_progress *pkt;
size_t alloclen;
line++; line++;
len--; len--;
pkt = git__malloc(sizeof(git_pkt_progress) + len);
GITERR_CHECK_ALLOC_ADD(&alloclen, sizeof(git_pkt_progress), len);
pkt = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_PROGRESS; pkt->type = GIT_PKT_PROGRESS;
@ -174,10 +187,14 @@ static int sideband_progress_pkt(git_pkt **out, const char *line, size_t len)
static int sideband_error_pkt(git_pkt **out, const char *line, size_t len) static int sideband_error_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_err *pkt; git_pkt_err *pkt;
size_t alloc_len;
line++; line++;
len--; len--;
pkt = git__malloc(sizeof(git_pkt_err) + len + 1);
GITERR_CHECK_ALLOC_ADD(&alloc_len, sizeof(git_pkt_err), len);
GITERR_CHECK_ALLOC_ADD(&alloc_len, alloc_len, 1);
pkt = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_ERR; pkt->type = GIT_PKT_ERR;
@ -197,6 +214,7 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
{ {
int error; int error;
git_pkt_ref *pkt; git_pkt_ref *pkt;
size_t alloclen;
pkt = git__malloc(sizeof(git_pkt_ref)); pkt = git__malloc(sizeof(git_pkt_ref));
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
@ -220,7 +238,8 @@ static int ref_pkt(git_pkt **out, const char *line, size_t len)
if (line[len - 1] == '\n') if (line[len - 1] == '\n')
--len; --len;
pkt->head.name = git__malloc(len + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
pkt->head.name = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt->head.name); GITERR_CHECK_ALLOC(pkt->head.name);
memcpy(pkt->head.name, line, len); memcpy(pkt->head.name, line, len);
@ -242,6 +261,7 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_ok *pkt; git_pkt_ok *pkt;
const char *ptr; const char *ptr;
size_t alloc_len;
pkt = git__malloc(sizeof(*pkt)); pkt = git__malloc(sizeof(*pkt));
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
@ -249,10 +269,14 @@ static int ok_pkt(git_pkt **out, const char *line, size_t len)
pkt->type = GIT_PKT_OK; pkt->type = GIT_PKT_OK;
line += 3; /* skip "ok " */ line += 3; /* skip "ok " */
ptr = strchr(line, '\n'); if (!(ptr = strchr(line, '\n'))) {
giterr_set(GITERR_NET, "Invalid packet line");
return -1;
}
len = ptr - line; len = ptr - line;
pkt->ref = git__malloc(len + 1); GITERR_CHECK_ALLOC_ADD(&alloc_len, len, 1);
pkt->ref = git__malloc(alloc_len);
GITERR_CHECK_ALLOC(pkt->ref); GITERR_CHECK_ALLOC(pkt->ref);
memcpy(pkt->ref, line, len); memcpy(pkt->ref, line, len);
@ -266,6 +290,7 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len)
{ {
git_pkt_ng *pkt; git_pkt_ng *pkt;
const char *ptr; const char *ptr;
size_t alloclen;
pkt = git__malloc(sizeof(*pkt)); pkt = git__malloc(sizeof(*pkt));
GITERR_CHECK_ALLOC(pkt); GITERR_CHECK_ALLOC(pkt);
@ -273,20 +298,28 @@ static int ng_pkt(git_pkt **out, const char *line, size_t len)
pkt->type = GIT_PKT_NG; pkt->type = GIT_PKT_NG;
line += 3; /* skip "ng " */ line += 3; /* skip "ng " */
ptr = strchr(line, ' '); if (!(ptr = strchr(line, ' '))) {
giterr_set(GITERR_NET, "Invalid packet line");
return -1;
}
len = ptr - line; len = ptr - line;
pkt->ref = git__malloc(len + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
pkt->ref = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt->ref); GITERR_CHECK_ALLOC(pkt->ref);
memcpy(pkt->ref, line, len); memcpy(pkt->ref, line, len);
pkt->ref[len] = '\0'; pkt->ref[len] = '\0';
line = ptr + 1; line = ptr + 1;
ptr = strchr(line, '\n'); if (!(ptr = strchr(line, '\n'))) {
giterr_set(GITERR_NET, "Invalid packet line");
return -1;
}
len = ptr - line; len = ptr - line;
pkt->msg = git__malloc(len + 1); GITERR_CHECK_ALLOC_ADD(&alloclen, len, 1);
pkt->msg = git__malloc(alloclen);
GITERR_CHECK_ALLOC(pkt->msg); GITERR_CHECK_ALLOC(pkt->msg);
memcpy(pkt->msg, line, len); memcpy(pkt->msg, line, len);
@ -459,7 +492,7 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
{ {
git_buf str = GIT_BUF_INIT; git_buf str = GIT_BUF_INIT;
char oid[GIT_OID_HEXSZ +1] = {0}; char oid[GIT_OID_HEXSZ +1] = {0};
unsigned int len; size_t len;
/* Prefer multi_ack_detailed */ /* Prefer multi_ack_detailed */
if (caps->multi_ack_detailed) if (caps->multi_ack_detailed)
@ -485,12 +518,19 @@ static int buffer_want_with_caps(const git_remote_head *head, transport_smart_ca
if (git_buf_oom(&str)) if (git_buf_oom(&str))
return -1; return -1;
len = (unsigned int) len = strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ +
(strlen("XXXXwant ") + GIT_OID_HEXSZ + 1 /* NUL */ + git_buf_len(&str) + 1 /* LF */;
git_buf_len(&str) + 1 /* LF */);
git_buf_grow(buf, git_buf_len(buf) + len); if (len > 0xffff) {
giterr_set(GITERR_NET,
"Tried to produce packet with invalid length %d", len);
return -1;
}
git_buf_grow_by(buf, len);
git_oid_fmt(oid, &head->oid); git_oid_fmt(oid, &head->oid);
git_buf_printf(buf, "%04xwant %s %s\n", len, oid, git_buf_cstr(&str)); git_buf_printf(buf,
"%04xwant %s %s\n", (unsigned int)len, oid, git_buf_cstr(&str));
git_buf_free(&str); git_buf_free(&str);
return git_buf_oom(buf); return git_buf_oom(buf);

View File

@ -685,7 +685,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
switch (pkt->type) { switch (pkt->type) {
case GIT_PKT_OK: case GIT_PKT_OK:
status = git__calloc(sizeof(push_status), 1); status = git__calloc(1, sizeof(push_status));
GITERR_CHECK_ALLOC(status); GITERR_CHECK_ALLOC(status);
status->msg = NULL; status->msg = NULL;
status->ref = git__strdup(((git_pkt_ok *)pkt)->ref); status->ref = git__strdup(((git_pkt_ok *)pkt)->ref);
@ -696,7 +696,7 @@ static int add_push_report_pkt(git_push *push, git_pkt *pkt)
} }
break; break;
case GIT_PKT_NG: case GIT_PKT_NG:
status = git__calloc(sizeof(push_status), 1); status = git__calloc(1, sizeof(push_status));
GITERR_CHECK_ALLOC(status); GITERR_CHECK_ALLOC(status);
status->ref = git__strdup(((git_pkt_ng *)pkt)->ref); status->ref = git__strdup(((git_pkt_ng *)pkt)->ref);
status->msg = git__strdup(((git_pkt_ng *)pkt)->msg); status->msg = git__strdup(((git_pkt_ng *)pkt)->msg);

View File

@ -1178,7 +1178,7 @@ static int winhttp_stream_alloc(winhttp_subtransport *t, winhttp_stream **stream
if (!stream) if (!stream)
return -1; return -1;
s = git__calloc(sizeof(winhttp_stream), 1); s = git__calloc(1, sizeof(winhttp_stream));
GITERR_CHECK_ALLOC(s); GITERR_CHECK_ALLOC(s);
s->parent.subtransport = &t->parent; s->parent.subtransport = &t->parent;
@ -1329,7 +1329,7 @@ int git_smart_subtransport_http(git_smart_subtransport **out, git_transport *own
if (!out) if (!out)
return -1; return -1;
t = git__calloc(sizeof(winhttp_subtransport), 1); t = git__calloc(1, sizeof(winhttp_subtransport));
GITERR_CHECK_ALLOC(t); GITERR_CHECK_ALLOC(t);
t->owner = (transport_smart *)owner; t->owner = (transport_smart *)owner;

View File

@ -84,10 +84,11 @@ int git_tree_entry_icmp(const git_tree_entry *e1, const git_tree_entry *e2)
static git_tree_entry *alloc_entry(const char *filename) static git_tree_entry *alloc_entry(const char *filename)
{ {
git_tree_entry *entry = NULL; git_tree_entry *entry = NULL;
size_t filename_len = strlen(filename); size_t filename_len = strlen(filename), tree_len;
entry = git__malloc(sizeof(git_tree_entry) + filename_len + 1); if (GIT_ADD_SIZET_OVERFLOW(&tree_len, sizeof(git_tree_entry), filename_len) ||
if (!entry) GIT_ADD_SIZET_OVERFLOW(&tree_len, tree_len, 1) ||
!(entry = git__malloc(tree_len)))
return NULL; return NULL;
memset(entry, 0x0, sizeof(git_tree_entry)); memset(entry, 0x0, sizeof(git_tree_entry));
@ -210,7 +211,8 @@ int git_tree_entry_dup(git_tree_entry **dest, const git_tree_entry *source)
assert(source); assert(source);
total_size = sizeof(git_tree_entry) + source->filename_len + 1; GITERR_CHECK_ALLOC_ADD(&total_size, sizeof(git_tree_entry), source->filename_len);
GITERR_CHECK_ALLOC_ADD(&total_size, total_size, 1);
copy = git__malloc(total_size); copy = git__malloc(total_size);
GITERR_CHECK_ALLOC(copy); GITERR_CHECK_ALLOC(copy);

View File

@ -184,7 +184,9 @@ static int check_invariant(struct tsort_run *stack, ssize_t stack_curr)
static int resize(struct tsort_store *store, size_t new_size) static int resize(struct tsort_store *store, size_t new_size)
{ {
if (store->alloc < new_size) { if (store->alloc < new_size) {
void **tempstore = git__realloc(store->storage, new_size * sizeof(void *)); void **tempstore;
tempstore = git__reallocarray(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

View File

@ -59,14 +59,13 @@ GIT_INLINE(char *) git__strdup(const char *str)
GIT_INLINE(char *) git__strndup(const char *str, size_t n) GIT_INLINE(char *) git__strndup(const char *str, size_t n)
{ {
size_t length = 0; size_t length = 0, alloclength;
char *ptr; char *ptr;
length = p_strnlen(str, n); length = p_strnlen(str, n);
ptr = (char*)git__malloc(length + 1); if (GIT_ADD_SIZET_OVERFLOW(&alloclength, length, 1) ||
!(ptr = git__malloc(alloclength)))
if (!ptr)
return NULL; return NULL;
if (length) if (length)
@ -80,7 +79,13 @@ GIT_INLINE(char *) git__strndup(const char *str, size_t n)
/* NOTE: This doesn't do null or '\0' checking. Watch those boundaries! */ /* NOTE: This doesn't do null or '\0' checking. Watch those boundaries! */
GIT_INLINE(char *) git__substrdup(const char *start, size_t n) GIT_INLINE(char *) git__substrdup(const char *start, size_t n)
{ {
char *ptr = (char*)git__malloc(n+1); char *ptr;
size_t alloclen;
if (GIT_ADD_SIZET_OVERFLOW(&alloclen, n, 1) ||
!(ptr = git__malloc(alloclen)))
return NULL;
memcpy(ptr, start, n); memcpy(ptr, start, n);
ptr[n] = '\0'; ptr[n] = '\0';
return ptr; return ptr;
@ -93,6 +98,26 @@ 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)
{
size_t newsize;
return GIT_MULTIPLY_SIZET_OVERFLOW(&newsize, nelem, elsize) ?
NULL : realloc(ptr, newsize);
}
/**
* 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);
@ -120,27 +145,6 @@ extern int git__strtol64(int64_t *n, const char *buff, const char **end_buf, int
extern void git__hexdump(const char *buffer, size_t n); extern void git__hexdump(const char *buffer, size_t n);
extern uint32_t git__hash(const void *key, int len, uint32_t seed); extern uint32_t git__hash(const void *key, int len, uint32_t seed);
/** @return true if p fits into the range of a size_t */
GIT_INLINE(int) git__is_sizet(git_off_t p)
{
size_t r = (size_t)p;
return p == (git_off_t)r;
}
/** @return true if p fits into the range of a uint32_t */
GIT_INLINE(int) git__is_uint32(size_t p)
{
uint32_t r = (uint32_t)p;
return p == (size_t)r;
}
/** @return true if p fits into the range of an unsigned long */
GIT_INLINE(int) git__is_ulong(git_off_t p)
{
unsigned long r = (unsigned long)p;
return p == (git_off_t)r;
}
/* 32-bit cross-platform rotl */ /* 32-bit cross-platform rotl */
#ifdef _MSC_VER /* use built-in method in MSVC */ #ifdef _MSC_VER /* use built-in method in MSVC */
# define git__rotl(v, s) (uint32_t)_rotl(v, s) # define git__rotl(v, s) (uint32_t)_rotl(v, s)

View File

@ -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 = new_size * sizeof(void *);
void *new_contents; void *new_contents;
/* Check for overflow */ new_contents = git__reallocarray(v->contents, new_size, sizeof(void *));
if (new_bytes / sizeof(void *) != new_size)
GITERR_CHECK_ALLOC(NULL);
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;
@ -51,7 +46,7 @@ int git_vector_dup(git_vector *v, const git_vector *src, git_vector_cmp cmp)
assert(v && src); assert(v && src);
bytes = src->length * sizeof(void *); GITERR_CHECK_ALLOC_MULTIPLY(&bytes, src->length, sizeof(void *));
v->_alloc_size = src->length; v->_alloc_size = src->length;
v->_cmp = cmp ? cmp : src->_cmp; v->_cmp = cmp ? cmp : src->_cmp;

View File

@ -11,16 +11,18 @@ git__DIR *git__opendir(const char *dir)
{ {
git_win32_path filter_w; git_win32_path filter_w;
git__DIR *new = NULL; git__DIR *new = NULL;
size_t dirlen; size_t dirlen, alloclen;
if (!dir || !git_win32__findfirstfile_filter(filter_w, dir)) if (!dir || !git_win32__findfirstfile_filter(filter_w, dir))
return NULL; return NULL;
dirlen = strlen(dir); dirlen = strlen(dir);
new = git__calloc(sizeof(*new) + dirlen + 1, 1); if (GIT_ADD_SIZET_OVERFLOW(&alloclen, sizeof(*new), dirlen) ||
if (!new) GIT_ADD_SIZET_OVERFLOW(&alloclen, alloclen, 1) ||
!(new = git__calloc(1, alloclen)))
return NULL; return NULL;
memcpy(new->dir, dir, dirlen); memcpy(new->dir, dir, dirlen);
new->h = FindFirstFileW(filter_w, &new->f); new->h = FindFirstFileW(filter_w, &new->f);

View File

@ -99,9 +99,7 @@ int git__utf8_to_16_alloc(wchar_t **dest, const char *src)
return -1; return -1;
} }
*dest = git__malloc(utf16_size * sizeof(wchar_t)); if (!(*dest = git__mallocarray(utf16_size, sizeof(wchar_t)))) {
if (!*dest) {
errno = ENOMEM; errno = ENOMEM;
return -1; return -1;
} }

View File

@ -134,7 +134,7 @@ int git_zstream_deflatebuf(git_buf *out, const void *in, size_t in_len)
while (!git_zstream_done(&zs)) { while (!git_zstream_done(&zs)) {
size_t step = git_zstream_suggest_output_len(&zs), written; size_t step = git_zstream_suggest_output_len(&zs), written;
if ((error = git_buf_grow(out, out->size + step)) < 0) if ((error = git_buf_grow_by(out, step)) < 0)
goto done; goto done;
written = out->asize - out->size; written = out->asize - out->size;

View File

@ -15,6 +15,28 @@ void test_buf_basic__resize(void)
git_buf_free(&buf1); git_buf_free(&buf1);
} }
void test_buf_basic__resize_incremental(void)
{
git_buf buf1 = GIT_BUF_INIT;
/* Presently, asking for 6 bytes will round up to 8. */
cl_git_pass(git_buf_puts(&buf1, "Hello"));
cl_assert_equal_i(5, buf1.size);
cl_assert_equal_i(8, buf1.asize);
/* Ensure an additional byte does not realloc. */
cl_git_pass(git_buf_grow_by(&buf1, 1));
cl_assert_equal_i(5, buf1.size);
cl_assert_equal_i(8, buf1.asize);
/* But requesting many does. */
cl_git_pass(git_buf_grow_by(&buf1, 16));
cl_assert_equal_i(5, buf1.size);
cl_assert(buf1.asize > 8);
git_buf_free(&buf1);
}
void test_buf_basic__printf(void) void test_buf_basic__printf(void)
{ {
git_buf buf2 = GIT_BUF_INIT; git_buf buf2 = GIT_BUF_INIT;

View File

@ -29,3 +29,13 @@ void test_buf_oom__grow(void)
git_buf_free(&buf); git_buf_free(&buf);
} }
void test_buf_oom__grow_by(void)
{
git_buf buf = GIT_BUF_INIT;
buf.size = SIZE_MAX-10;
cl_assert(git_buf_grow_by(&buf, 50) == -1);
cl_assert(git_buf_oom(&buf));
}

View File

@ -109,3 +109,68 @@ void test_core_errors__restore(void)
cl_assert_equal_i(42, giterr_last()->klass); cl_assert_equal_i(42, giterr_last()->klass);
cl_assert_equal_s("Foo: bar", giterr_last()->message); cl_assert_equal_s("Foo: bar", giterr_last()->message);
} }
static int test_arraysize_multiply(size_t nelem, size_t size)
{
size_t out;
GITERR_CHECK_ALLOC_MULTIPLY(&out, nelem, size);
return 0;
}
void test_core_errors__integer_overflow_alloc_multiply(void)
{
cl_git_pass(test_arraysize_multiply(10, 10));
cl_git_pass(test_arraysize_multiply(1000, 1000));
cl_git_pass(test_arraysize_multiply(SIZE_MAX/sizeof(void *), sizeof(void *)));
cl_git_pass(test_arraysize_multiply(0, 10));
cl_git_pass(test_arraysize_multiply(10, 0));
cl_git_fail(test_arraysize_multiply(SIZE_MAX-1, sizeof(void *)));
cl_git_fail(test_arraysize_multiply((SIZE_MAX/sizeof(void *))+1, sizeof(void *)));
cl_assert_equal_i(GITERR_NOMEMORY, giterr_last()->klass);
cl_assert_equal_s("Out of memory", giterr_last()->message);
}
static int test_arraysize_add(size_t one, size_t two)
{
size_t out;
GITERR_CHECK_ALLOC_ADD(&out, one, two);
return 0;
}
void test_core_errors__integer_overflow_alloc_add(void)
{
cl_git_pass(test_arraysize_add(10, 10));
cl_git_pass(test_arraysize_add(1000, 1000));
cl_git_pass(test_arraysize_add(SIZE_MAX-10, 10));
cl_git_fail(test_arraysize_multiply(SIZE_MAX-1, 2));
cl_git_fail(test_arraysize_multiply(SIZE_MAX, SIZE_MAX));
cl_assert_equal_i(GITERR_NOMEMORY, giterr_last()->klass);
cl_assert_equal_s("Out of memory", giterr_last()->message);
}
void test_core_errors__integer_overflow_sets_oom(void)
{
size_t out;
giterr_clear();
cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX-1, 1));
cl_assert_equal_p(NULL, giterr_last());
giterr_clear();
cl_assert(!GIT_ADD_SIZET_OVERFLOW(&out, 42, 69));
cl_assert_equal_p(NULL, giterr_last());
giterr_clear();
cl_assert(GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX, SIZE_MAX));
cl_assert_equal_i(GITERR_NOMEMORY, giterr_last()->klass);
cl_assert_equal_s("Out of memory", giterr_last()->message);
giterr_clear();
cl_assert(GIT_ADD_SIZET_OVERFLOW(&out, SIZE_MAX, SIZE_MAX));
cl_assert_equal_i(GITERR_NOMEMORY, giterr_last()->klass);
cl_assert_equal_s("Out of memory", giterr_last()->message);
}