Skip to content

Commit 6930731

Browse files
committed
Merge branch 'rs/pull-signed-tag' into maint
When "git merge-recursive" works on history with many criss-cross merges in "verbose" mode, the names the command assigns to the virtual merge bases could have overwritten each other by unintended reuse of the same piece of memory. * rs/pull-signed-tag: commit: use FLEX_ARRAY in struct merge_remote_desc merge-recursive: fix verbose output for multiple base trees commit: factor out set_merge_remote_desc() commit: use xstrdup() in get_merge_parent()
2 parents 86df11b + 5447a76 commit 6930731

File tree

4 files changed

+33
-12
lines changed

4 files changed

+33
-12
lines changed

commit.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1576,6 +1576,15 @@ int commit_tree_extended(const char *msg, size_t msg_len,
15761576
return result;
15771577
}
15781578

1579+
void set_merge_remote_desc(struct commit *commit,
1580+
const char *name, struct object *obj)
1581+
{
1582+
struct merge_remote_desc *desc;
1583+
FLEX_ALLOC_STR(desc, name, name);
1584+
desc->obj = obj;
1585+
commit->util = desc;
1586+
}
1587+
15791588
struct commit *get_merge_parent(const char *name)
15801589
{
15811590
struct object *obj;
@@ -1585,13 +1594,8 @@ struct commit *get_merge_parent(const char *name)
15851594
return NULL;
15861595
obj = parse_object(oid.hash);
15871596
commit = (struct commit *)peel_to_type(name, 0, obj, OBJ_COMMIT);
1588-
if (commit && !commit->util) {
1589-
struct merge_remote_desc *desc;
1590-
desc = xmalloc(sizeof(*desc));
1591-
desc->obj = obj;
1592-
desc->name = strdup(name);
1593-
commit->util = desc;
1594-
}
1597+
if (commit && !commit->util)
1598+
set_merge_remote_desc(commit, name, obj);
15951599
return commit;
15961600
}
15971601

commit.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,9 +356,11 @@ extern void for_each_mergetag(each_mergetag_fn fn, struct commit *commit, void *
356356

357357
struct merge_remote_desc {
358358
struct object *obj; /* the named object, could be a tag */
359-
const char *name;
359+
char name[FLEX_ARRAY];
360360
};
361361
#define merge_remote_util(commit) ((struct merge_remote_desc *)((commit)->util))
362+
extern void set_merge_remote_desc(struct commit *commit,
363+
const char *name, struct object *obj);
362364

363365
/*
364366
* Given "name" from the command line to merge, find the commit object

merge-recursive.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,12 +42,9 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two,
4242
static struct commit *make_virtual_commit(struct tree *tree, const char *comment)
4343
{
4444
struct commit *commit = alloc_commit_node();
45-
struct merge_remote_desc *desc = xmalloc(sizeof(*desc));
4645

47-
desc->name = comment;
48-
desc->obj = (struct object *)commit;
46+
set_merge_remote_desc(commit, comment, (struct object *)commit);
4947
commit->tree = tree;
50-
commit->util = desc;
5148
commit->object.parsed = 1;
5249
return commit;
5350
}

t/t3030-merge-recursive.sh

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -660,4 +660,22 @@ test_expect_success 'merging with triple rename across D/F conflict' '
660660
git merge other
661661
'
662662

663+
test_expect_success 'merge-recursive remembers the names of all base trees' '
664+
git reset --hard HEAD &&
665+
666+
# more trees than static slots used by oid_to_hex()
667+
for commit in $c0 $c2 $c4 $c5 $c6 $c7
668+
do
669+
git rev-parse "$commit^{tree}"
670+
done >trees &&
671+
672+
# ignore the return code -- it only fails because the input is weird
673+
test_must_fail git -c merge.verbosity=5 merge-recursive $(cat trees) -- $c1 $c3 >out &&
674+
675+
# merge-recursive prints in reverse order, but we do not care
676+
sort <trees >expect &&
677+
sed -n "s/^virtual //p" out | sort >actual &&
678+
test_cmp expect actual
679+
'
680+
663681
test_done

0 commit comments

Comments
 (0)