Skip to content

Commit b8ba412

Browse files
peffgitster
authored andcommitted
tree-diff: avoid alloca for large allocations
Commit 72441af (tree-diff: rework diff_tree() to generate diffs for multiparent cases as well, 2014-04-07) introduced the use of alloca so that the common cases of commits with 1 or 2 parents would not be adversely affected by going through the multi-parent code. However, our xalloca is not ideal when the number of parents grows very large: 1. If the requested size is too large for our stack, alloca() has no way to tell us, and we simply segfault while trying to access the memory. 2. It does not use our usual memory_limit_check() logic. I measured, and alloca is indeed buying us a very small speedup over xmalloc()/free(). So we'd want to keep something like it. This patch simply puts a conditional in place at each callsite: we use alloca for common known-small numbers of parents, and otherwise use the heap. We are technically still vulnerable to (1), but no more so than if we simply put a few dozen bytes on the stack, which we must do all the time anyway. And likewise, we technically miss a memory limit check if it is tiny, but such a limit is pointless. An alternative to this would be implement something like: struct tree *tp, tp_fallback[2]; if (nparent <= ARRAY_SIZE(tp_fallback)) tp = tp_fallback; else ALLOC_ARRAY(tp, nparent); ... if (tp != tp_fallback) free(tp); That would let us drop our xalloca() portability code entirely. But in my measurements, this seemed to perform slightly worse than the xalloca solution. Note in the example above, and in the patch below, I've used ALLOC_ARRAY() to replace the manual xmalloc(nr * sizeof(*x)). Besides being shorter, this has the bonus that one cannot accidentally overflow a size_t during that computation. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 7654286 commit b8ba412

File tree

1 file changed

+16
-6
lines changed

1 file changed

+16
-6
lines changed

tree-diff.c

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,16 @@
1414
*/
1515
#define S_IFXMIN_NEQ S_DIFFTREE_IFXMIN_NEQ
1616

17+
#define FAST_ARRAY_ALLOC(x, nr) do { \
18+
if ((nr) <= 2) \
19+
(x) = xalloca((nr) * sizeof(*(x))); \
20+
else \
21+
ALLOC_ARRAY((x), nr); \
22+
} while(0)
23+
#define FAST_ARRAY_FREE(x, nr) do { \
24+
if ((nr) > 2) \
25+
free((x)); \
26+
} while(0)
1727

1828
static struct combine_diff_path *ll_diff_tree_paths(
1929
struct combine_diff_path *p, const unsigned char *sha1,
@@ -265,7 +275,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
265275
if (recurse) {
266276
const unsigned char **parents_sha1;
267277

268-
parents_sha1 = xalloca(nparent * sizeof(parents_sha1[0]));
278+
FAST_ARRAY_ALLOC(parents_sha1, nparent);
269279
for (i = 0; i < nparent; ++i) {
270280
/* same rule as in emitthis */
271281
int tpi_valid = tp && !(tp[i].entry.mode & S_IFXMIN_NEQ);
@@ -277,7 +287,7 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
277287
strbuf_add(base, path, pathlen);
278288
strbuf_addch(base, '/');
279289
p = ll_diff_tree_paths(p, sha1, parents_sha1, nparent, base, opt);
280-
xalloca_free(parents_sha1);
290+
FAST_ARRAY_FREE(parents_sha1, nparent);
281291
}
282292

283293
strbuf_setlen(base, old_baselen);
@@ -402,8 +412,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
402412
void *ttree, **tptree;
403413
int i;
404414

405-
tp = xalloca(nparent * sizeof(tp[0]));
406-
tptree = xalloca(nparent * sizeof(tptree[0]));
415+
FAST_ARRAY_ALLOC(tp, nparent);
416+
FAST_ARRAY_ALLOC(tptree, nparent);
407417

408418
/*
409419
* load parents first, as they are probably already cached.
@@ -531,8 +541,8 @@ static struct combine_diff_path *ll_diff_tree_paths(
531541
free(ttree);
532542
for (i = nparent-1; i >= 0; i--)
533543
free(tptree[i]);
534-
xalloca_free(tptree);
535-
xalloca_free(tp);
544+
FAST_ARRAY_FREE(tptree, nparent);
545+
FAST_ARRAY_FREE(tp, nparent);
536546

537547
return p;
538548
}

0 commit comments

Comments
 (0)