xdiff: introduce XDL_ALLOC_GROW()

Add a helper to grow an array. This is analogous to ALLOC_GROW() in the rest of the codebase but returns −1 on allocation failure to accommodate other users of libxdiff such as libgit2. It will also return a error if the multiplication overflows while calculating the new allocation size. Note that this keeps doubling on reallocation like the code it is replacing rather than increasing the existing size by half like ALLOC_GROW(). It does however copy ALLOC_GROW()'s trick of adding a small amount to the new allocation to avoid a lot of reallocations at small sizes. Note that xdl_alloc_grow_helper() uses long rather than size_t for `nr` and `alloc` to match the existing code. Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Phillip Wood committed Jul 8, 2022 at 16:25 UTC f7b587bf656574103a0a2ad9c2337b0d15c0e92d
4 files changed +33 -16
xdiff/xmacros.h
+10
@@ -58,4 +58,14 @@ do { \
58 /* Allocate an array of nr zeroed out elements, returns NULL on failure */
59 #define XDL_CALLOC_ARRAY(p, nr) ((p) = xdl_calloc(nr, sizeof(*(p))))
60
61 +/*
62 + * Ensure array p can accommodate at least nr elements, growing the
63 + * array and updating alloc (which is the number of allocated
64 + * elements) as necessary. Frees p and returns -1 on failure, returns
65 + * 0 on success
66 + */
67 +#define XDL_ALLOC_GROW(p, nr, alloc) \
68 + (-!((nr) <= (alloc) || \
69 + ((p) = xdl_alloc_grow_helper((p), (nr), &(alloc), sizeof(*(p))))))
70 +
71 #endif /* #if !defined(XMACROS_H) */
xdiff/xprepare.c
+4 -15
@@ -111,7 +111,6 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t
111 long hi;
112 char const *line;
113 xdlclass_t *rcrec;
114 - xdlclass_t **rcrecs;
114
115 line = rec->ptr;
116 hi = (long) XDL_HASHLONG(rec->ha, cf->hbits);
@@ -127,14 +126,8 @@ static int xdl_classify_record(unsigned int pass, xdlclassifier_t *cf, xrecord_t
126 return -1;
127 }
128 rcrec->idx = cf->count++;
130 - if (cf->count > cf->alloc) {
131 - cf->alloc *= 2;
132 - if (!(rcrecs = (xdlclass_t **) xdl_realloc(cf->rcrecs, cf->alloc * sizeof(xdlclass_t *)))) {
133 -
129 + if (XDL_ALLOC_GROW(cf->rcrecs, cf->count, cf->alloc))
130 return -1;
135 - }
136 - cf->rcrecs = rcrecs;
137 - }
131 cf->rcrecs[rcrec->idx] = rcrec;
132 rcrec->line = line;
133 rcrec->size = rec->size;
@@ -163,7 +156,7 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
156 unsigned long hav;
157 char const *blk, *cur, *top, *prev;
158 xrecord_t *crec;
166 - xrecord_t **recs, **rrecs;
159 + xrecord_t **recs;
160 xrecord_t **rhash;
161 unsigned long *ha;
162 char *rchg;
@@ -190,12 +183,8 @@ static int xdl_prepare_ctx(unsigned int pass, mmfile_t *mf, long narec, xpparam_
183 for (top = blk + bsize; cur < top; ) {
184 prev = cur;
185 hav = xdl_hash_record(&cur, top, xpp->flags);
193 - if (nrec >= narec) {
194 - narec *= 2;
195 - if (!(rrecs = (xrecord_t **) xdl_realloc(recs, narec * sizeof(xrecord_t *))))
196 - goto abort;
197 - recs = rrecs;
198 - }
186 + if (XDL_ALLOC_GROW(recs, nrec + 1, narec))
187 + goto abort;
188 if (!(crec = xdl_cha_alloc(&xdf->rcha)))
189 goto abort;
190 crec->ptr = prev;
xdiff/xutils.c
+17
@@ -432,3 +432,20 @@ int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
432
433 return 0;
434 }
435 +
436 +void* xdl_alloc_grow_helper(void *p, long nr, long *alloc, size_t size)
437 +{
438 + void *tmp = NULL;
439 + size_t n = ((LONG_MAX - 16) / 2 >= *alloc) ? 2 * *alloc + 16 : LONG_MAX;
440 + if (nr > n)
441 + n = nr;
442 + if (SIZE_MAX / size >= n)
443 + tmp = xdl_realloc(p, n * size);
444 + if (tmp) {
445 + *alloc = n;
446 + } else {
447 + xdl_free(p);
448 + *alloc = 0;
449 + }
450 + return tmp;
451 +}
xdiff/xutils.h
+2 -1
@@ -42,6 +42,7 @@ int xdl_emit_hunk_hdr(long s1, long c1, long s2, long c2,
42 int xdl_fall_back_diff(xdfenv_t *diff_env, xpparam_t const *xpp,
43 int line1, int count1, int line2, int count2);
44
45 -
45 +/* Do not call this function, use XDL_ALLOC_GROW instead */
46 +void* xdl_alloc_grow_helper(void* p, long nr, long* alloc, size_t size);
47
48 #endif /* #if !defined(XUTILS_H) */