Skip to content

Commit 7b61bd1

Browse files
peffgitster
authored andcommitted
tree-diff: respect max_allowed_tree_depth
When diffing trees, we recurse to handle subtrees. That means we may run out of stack space and segfault. Let's teach this code path about core.maxTreeDepth in order to fail more gracefully. As with the previous patch, we have no way to return an error (and other tree-loading problems would just cause us to die()). So we'll likewise call die() if we exceed the maximum depth. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 670a1da commit 7b61bd1

File tree

2 files changed

+24
-8
lines changed

2 files changed

+24
-8
lines changed

t/t6700-tree-depth.sh

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,4 +81,13 @@ test_expect_success 'default limit for rev-list fails gracefully' '
8181
test_must_fail git rev-list --objects big >/dev/null
8282
'
8383

84+
test_expect_success 'limit recursion of diff-tree -r' '
85+
git $small_ok diff-tree -r $EMPTY_TREE small &&
86+
test_must_fail git $small_no diff-tree -r $EMPTY_TREE small
87+
'
88+
89+
test_expect_success 'default limit for diff-tree fails gracefully' '
90+
test_must_fail git diff-tree -r $EMPTY_TREE big
91+
'
92+
8493
test_done

tree-diff.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include "hash.h"
88
#include "tree.h"
99
#include "tree-walk.h"
10+
#include "environment.h"
1011

1112
/*
1213
* Some mode bits are also used internally for computations.
@@ -45,7 +46,8 @@
4546
static struct combine_diff_path *ll_diff_tree_paths(
4647
struct combine_diff_path *p, const struct object_id *oid,
4748
const struct object_id **parents_oid, int nparent,
48-
struct strbuf *base, struct diff_options *opt);
49+
struct strbuf *base, struct diff_options *opt,
50+
int depth);
4951
static void ll_diff_tree_oid(const struct object_id *old_oid,
5052
const struct object_id *new_oid,
5153
struct strbuf *base, struct diff_options *opt);
@@ -196,7 +198,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
196198
static struct combine_diff_path *emit_path(struct combine_diff_path *p,
197199
struct strbuf *base, struct diff_options *opt, int nparent,
198200
struct tree_desc *t, struct tree_desc *tp,
199-
int imin)
201+
int imin, int depth)
200202
{
201203
unsigned short mode;
202204
const char *path;
@@ -302,7 +304,8 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
302304

303305
strbuf_add(base, path, pathlen);
304306
strbuf_addch(base, '/');
305-
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
307+
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt,
308+
depth + 1);
306309
FAST_ARRAY_FREE(parents_oid, nparent);
307310
}
308311

@@ -423,12 +426,16 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
423426
static struct combine_diff_path *ll_diff_tree_paths(
424427
struct combine_diff_path *p, const struct object_id *oid,
425428
const struct object_id **parents_oid, int nparent,
426-
struct strbuf *base, struct diff_options *opt)
429+
struct strbuf *base, struct diff_options *opt,
430+
int depth)
427431
{
428432
struct tree_desc t, *tp;
429433
void *ttree, **tptree;
430434
int i;
431435

436+
if (depth > max_allowed_tree_depth)
437+
die("exceeded maximum allowed tree depth");
438+
432439
FAST_ARRAY_ALLOC(tp, nparent);
433440
FAST_ARRAY_ALLOC(tptree, nparent);
434441

@@ -522,7 +529,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
522529

523530
/* D += {δ(t,pi) if pi=p[imin]; "+a" if pi > p[imin]} */
524531
p = emit_path(p, base, opt, nparent,
525-
&t, tp, imin);
532+
&t, tp, imin, depth);
526533

527534
skip_emit_t_tp:
528535
/* t↓, ∀ pi=p[imin] pi↓ */
@@ -534,7 +541,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
534541
else if (cmp < 0) {
535542
/* D += "+t" */
536543
p = emit_path(p, base, opt, nparent,
537-
&t, /*tp=*/NULL, -1);
544+
&t, /*tp=*/NULL, -1, depth);
538545

539546
/* t↓ */
540547
update_tree_entry(&t);
@@ -550,7 +557,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
550557
}
551558

552559
p = emit_path(p, base, opt, nparent,
553-
/*t=*/NULL, tp, imin);
560+
/*t=*/NULL, tp, imin, depth);
554561

555562
skip_emit_tp:
556563
/* ∀ pi=p[imin] pi↓ */
@@ -572,7 +579,7 @@ struct combine_diff_path *diff_tree_paths(
572579
const struct object_id **parents_oid, int nparent,
573580
struct strbuf *base, struct diff_options *opt)
574581
{
575-
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt);
582+
p = ll_diff_tree_paths(p, oid, parents_oid, nparent, base, opt, 0);
576583

577584
/*
578585
* free pre-allocated last element, if any

0 commit comments

Comments
 (0)