Skip to content

Commit aab3b9a

Browse files
committed
read-tree A B C: do not create a bogus index and do not segfault
"git read-tree A B C..." without the "-m" (merge) option is a way to read these trees on top of each other to get an overlay of them. An ancient commit ee6566e (Rewrite read-tree, 2005-09-05) passed the ADD_CACHE_SKIP_DFCHECK flag when calling add_index_entry() to add the paths obtained from these trees to the index, but it is an incorrect use of the flag. The flag is meant to be used by callers who know the addition of the entry does not introduce a D/F conflict to the index in order to avoid the overhead of checking. This bug resulted in a bogus index that records both "x" and "x/z" as a blob after reading three trees that have paths ("x"), ("x", "y"), and ("x/z", "y") respectively. 34110cd (Make 'unpack_trees()' have a separate source and destination index, 2008-03-06) refactored the callsites of add_index_entry() incorrectly and added more codepaths that use this flag when it shouldn't be used. Also, 0190457 (Move 'unpack_trees()' over to 'traverse_trees()' interface, 2008-03-05) introduced a bug to call add_index_entry() for the tree that does not have the path in it, passing NULL as a cache entry. This caused reading multiple trees, one of which has path "x" but another doesn't, to segfault. Signed-off-by: Junio C Hamano <[email protected]>
1 parent ea02eef commit aab3b9a

File tree

2 files changed

+34
-3
lines changed

2 files changed

+34
-3
lines changed

t/t1008-read-tree-overlay.sh

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
#!/bin/sh
2+
3+
test_description='test multi-tree read-tree without merging'
4+
5+
. ./test-lib.sh
6+
7+
test_expect_success setup '
8+
echo one >a &&
9+
git add a &&
10+
git commit -m initial &&
11+
git tag initial &&
12+
echo two >b &&
13+
git add b &&
14+
git commit -m second &&
15+
git checkout -b side initial &&
16+
echo three >a &&
17+
mkdir b &&
18+
echo four >b/c &&
19+
git add b/c &&
20+
git commit -m third
21+
'
22+
23+
test_expect_success 'multi-read' '
24+
git read-tree initial master side &&
25+
(echo a; echo b/c) >expect &&
26+
git ls-files >actual &&
27+
test_cmp expect actual
28+
'
29+
30+
test_done
31+

unpack-trees.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ static void add_entry(struct unpack_trees_options *o, struct cache_entry *ce,
4949
memcpy(new, ce, size);
5050
new->next = NULL;
5151
new->ce_flags = (new->ce_flags & ~clear) | set;
52-
add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|ADD_CACHE_SKIP_DFCHECK);
52+
add_index_entry(&o->result, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
5353
}
5454

5555
/* Unlink the last component and attempt to remove leading
@@ -283,9 +283,9 @@ static int unpack_nondirectories(int n, unsigned long mask, unsigned long dirmas
283283
if (o->merge)
284284
return call_unpack_fn(src, o);
285285

286-
n += o->merge;
287286
for (i = 0; i < n; i++)
288-
add_entry(o, src[i], 0, 0);
287+
if (src[i] && src[i] != o->df_conflict_entry)
288+
add_entry(o, src[i], 0, 0);
289289
return 0;
290290
}
291291

0 commit comments

Comments
 (0)