Testing for realloc and size limit can be done with only one test per loop. Make it so and fix a theoretical off-by-one comparison error in the process. The output buffer memory allocation is also bounded by max_size when specified. Finally make some variable unsigned to allow the handling of files up to 4GB in size instead of 2GB. Signed-off-by: Nicolas Pitre <nico@xxxxxxx> --- diff-delta.c | 24 ++++++++++++++---------- 1 files changed, 14 insertions(+), 10 deletions(-) 95c1d1f82a8e36ab1e46b8186ecb34f441914961 diff --git a/diff-delta.c b/diff-delta.c index c2f656a..ac992e2 100644 --- a/diff-delta.c +++ b/diff-delta.c @@ -148,16 +148,20 @@ static void delta_cleanup(bdfile_t *bdf) cha_free(&bdf->cha); } +/* provide the size of the copy opcode given the block offset and size */ #define COPYOP_SIZE(o, s) \ (!!(o & 0xff) + !!(o & 0xff00) + !!(o & 0xff0000) + !!(o & 0xff000000) + \ !!(s & 0xff) + !!(s & 0xff00) + 1) +/* the maximum size for any opcode */ +#define MAX_OP_SIZE COPYOP_SIZE(0xffffffff, 0xffffffff) + void *diff_delta(void *from_buf, unsigned long from_size, void *to_buf, unsigned long to_size, unsigned long *delta_size, unsigned long max_size) { - int i, outpos, outsize, inscnt, csize, msize, moff; + unsigned int i, outpos, outsize, inscnt, csize, msize, moff; unsigned int fp; const unsigned char *ref_data, *ref_top, *data, *top, *ptr1, *ptr2; unsigned char *out, *orig; @@ -169,6 +173,8 @@ void *diff_delta(void *from_buf, unsigne outpos = 0; outsize = 8192; + if (max_size && outsize >= max_size) + outsize = max_size + MAX_OP_SIZE + 1; out = malloc(outsize); if (!out) { delta_cleanup(&bdf); @@ -259,17 +265,15 @@ void *diff_delta(void *from_buf, unsigne *orig = i; } - if (max_size && outpos > max_size) { - free(out); - delta_cleanup(&bdf); - return NULL; - } - - /* next time around the largest possible output is 1 + 4 + 3 */ - if (outpos > outsize - 8) { + if (outpos >= outsize - MAX_OP_SIZE) { void *tmp = out; outsize = outsize * 3 / 2; - out = realloc(out, outsize); + if (max_size && outsize >= max_size) + outsize = max_size + MAX_OP_SIZE + 1; + if (max_size && outpos > max_size) + out = NULL; + else + out = realloc(out, outsize); if (!out) { free(tmp); delta_cleanup(&bdf); -- 1.2.2.g6643-dirty - : send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html