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 <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Jeff King committed
Aug 31, 2023 at 02:22 UTC
7b61bd18b13223064db01d89e3b8af106661efd5
2 files changed
+24
-8
t/t6700-tree-depth.sh
+9
@@ -81,4 +81,13 @@ test_expect_success 'default limit for rev-list fails gracefully' '
81
test_must_fail git rev-list --objects big >/dev/null
82
'
83
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
+
93
test_done
tree-diff.c
+15
-8
@@ -7,6 +7,7 @@
7
#include "hash.h"
8
#include "tree.h"
9
#include "tree-walk.h"
10
+#include "environment.h"
11
12
/*
13
* Some mode bits are also used internally for computations.
@@ -45,7 +46,8 @@
46
static struct combine_diff_path *ll_diff_tree_paths(
47
struct combine_diff_path *p, const struct object_id *oid,
48
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);
51
static void ll_diff_tree_oid(const struct object_id *old_oid,
52
const struct object_id *new_oid,
53
struct strbuf *base, struct diff_options *opt);
@@ -196,7 +198,7 @@ static struct combine_diff_path *path_appendnew(struct combine_diff_path *last,
198
static struct combine_diff_path *emit_path(struct combine_diff_path *p,
199
struct strbuf *base, struct diff_options *opt, int nparent,
200
struct tree_desc *t, struct tree_desc *tp,
199
- int imin)
201
+ int imin, int depth)
202
{
203
unsigned short mode;
204
const char *path;
@@ -302,7 +304,8 @@ static struct combine_diff_path *emit_path(struct combine_diff_path *p,
304
305
strbuf_add(base, path, pathlen);
306
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);
309
FAST_ARRAY_FREE(parents_oid, nparent);
310
}
311
@@ -423,12 +426,16 @@ static inline void update_tp_entries(struct tree_desc *tp, int nparent)
426
static struct combine_diff_path *ll_diff_tree_paths(
427
struct combine_diff_path *p, const struct object_id *oid,
428
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)
431
{
432
struct tree_desc t, *tp;
433
void *ttree, **tptree;
434
int i;
435
436
+ if (depth > max_allowed_tree_depth)
437
+ die("exceeded maximum allowed tree depth");
438
+
439
FAST_ARRAY_ALLOC(tp, nparent);
440
FAST_ARRAY_ALLOC(tptree, nparent);
441
@@ -522,7 +529,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
529
530
/* D += {δ(t,pi) if pi=p[imin]; "+a" if pi > p[imin]} */
531
p = emit_path(p, base, opt, nparent,
525
- &t, tp, imin);
532
+ &t, tp, imin, depth);
533
534
skip_emit_t_tp:
535
/* t↓, ∀ pi=p[imin] pi↓ */
@@ -534,7 +541,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
541
else if (cmp < 0) {
542
/* D += "+t" */
543
p = emit_path(p, base, opt, nparent,
537
- &t, /*tp=*/NULL, -1);
544
+ &t, /*tp=*/NULL, -1, depth);
545
546
/* t↓ */
547
update_tree_entry(&t);
@@ -550,7 +557,7 @@ static struct combine_diff_path *ll_diff_tree_paths(
557
}
558
559
p = emit_path(p, base, opt, nparent,
553
- /*t=*/NULL, tp, imin);
560
+ /*t=*/NULL, tp, imin, depth);
561
562
skip_emit_tp:
563
/* ∀ pi=p[imin] pi↓ */
@@ -572,7 +579,7 @@ struct combine_diff_path *diff_tree_paths(
579
const struct object_id **parents_oid, int nparent,
580
struct strbuf *base, struct diff_options *opt)
581
{
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);
583
584
/*
585
* free pre-allocated last element, if any