[PATCH] Fix segfault in merge-recursive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



When there is no "common" tree (for whatever reason), we must not
throw a segmentation fault.

Noticed by Dave O.

Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx>
---

	Sorry, did not have much time, so I only fixed the segfault.  
	Could you verify that the result is correct?

 merge-recursive.c          |   23 +++++--
 t/t3031-merge-criscross.sh |  135 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 151 insertions(+), 7 deletions(-)
 create mode 100755 t/t3031-merge-criscross.sh

diff --git a/merge-recursive.c b/merge-recursive.c
index a3721ef..920ccc1 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -176,17 +176,26 @@ static int git_merge_trees(int index_only,
 		opts.index_only = 1;
 	else
 		opts.update = 1;
-	opts.merge = 1;
-	opts.head_idx = 2;
 	opts.fn = threeway_merge;
 	opts.src_index = &the_index;
 	opts.dst_index = &the_index;
 
-	init_tree_desc_from_tree(t+0, common);
-	init_tree_desc_from_tree(t+1, head);
-	init_tree_desc_from_tree(t+2, merge);
+	if (common) {
+		opts.merge = 1;
+		opts.head_idx = 2;
+		init_tree_desc_from_tree(t+0, common);
+		init_tree_desc_from_tree(t+1, head);
+		init_tree_desc_from_tree(t+2, merge);
+		rc = unpack_trees(3, t, &opts);
+	}
+	else {
+		opts.merge = 0;
+		opts.head_idx = 1;
+		init_tree_desc_from_tree(t+0, head);
+		init_tree_desc_from_tree(t+1, merge);
+		rc = unpack_trees(2, t, &opts);
+	}
 
-	rc = unpack_trees(3, t, &opts);
 	cache_tree_free(&active_cache_tree);
 	return rc;
 }
@@ -1152,7 +1161,7 @@ int merge_trees(struct merge_options *o,
 		common = shift_tree_object(head, common);
 	}
 
-	if (sha_eq(common->object.sha1, merge->object.sha1)) {
+	if (common && sha_eq(common->object.sha1, merge->object.sha1)) {
 		output(o, 0, "Already uptodate!");
 		*result = head;
 		return 1;
diff --git a/t/t3031-merge-criscross.sh b/t/t3031-merge-criscross.sh
new file mode 100755
index 0000000..525afea
--- /dev/null
+++ b/t/t3031-merge-criscross.sh
@@ -0,0 +1,135 @@
+#!/bin/sh
+
+test_description='merge-recursive backend test'
+
+. ./test-lib.sh
+
+#         A      <- create some files
+#        / \
+#       B   C    <- cause rename/delete conflicts between B and C
+#      /     \
+# ->  1       1  <- merge-bases for F and G: B1, C1
+#     |\     /|
+#     2 D   E 2
+#     | |   | |
+#     | 1   1 |  <- overload rename_limit in E1
+#     |  \ /  |
+#     |   X   |
+#     |  / \  |
+#     | /   \ |
+#     |/     \|
+#     F       G  <- merge E into B, D into C
+#      \     /
+#       \   /
+#        \ /
+#         H      <- recursive merge crashes
+#
+
+# initialize
+test_expect_success 'setup' '
+	mkdir data &&
+
+	test_debug create a bunch of files &&
+	n=1 &&
+	while test $n -le 1000
+	do
+		echo $n > data/$n &&
+		n=$(($n+1)) ||
+		break
+	done &&
+
+	test_debug check them in &&
+	git add data &&
+	git commit -m A &&
+	git branch A &&
+
+	test_debug remove some files in one branch &&
+	git checkout -b B A &&
+	git rm data/99* &&
+	git add data &&
+	git commit -m B &&
+
+	test_debug few more commits on B &&
+	echo testB > data/testB &&
+	git add data &&
+	git commit -m B1 &&
+
+	test_debug with a branch off of it &&
+	git branch D &&
+
+	echo testB2 > data/testB2 &&
+	git add data &&
+	git commit -m B2 &&
+
+	test_debug put some commits on D &&
+	git checkout D &&
+	echo testD > data/testD &&
+	git add data &&
+	git commit -m D &&
+
+	echo testD1 > data/testD1 &&
+	git add data &&
+	git commit -m D1 &&
+
+	test_debug back up to the top, create another branch and cause a rename  &&
+	test_debug conflict with the files we deleted earlier &&
+	git checkout -b C A &&
+	git rm --cached data/99* &&
+	rename "s!/9!/moved-9!" data/99* &&
+	git add data &&
+	git commit -m C &&
+
+	test_debug few more commits on C &&
+	echo testC > data/testC &&
+	git add data &&
+	git commit -m C1 &&
+
+	test_debug with a branch off of it &&
+	git branch E &&
+
+	echo testC2 > data/testC2 &&
+	git add data &&
+	git commit -m C2 &&
+
+	test_debug put a commits on E &&
+	git checkout E &&
+	echo testE > data/testE &&
+	git add data &&
+	git commit -m E &&
+
+	test_debug and now, overload add/delete &&
+	git rm data/[123456]* &&
+	n=10000 &&
+	while test $n -le 11000
+	do
+		echo $n > data/$n &&
+		n=$(($n+1)) ||
+		break
+	done &&
+	git add data &&
+	git commit -m E1 &&
+
+
+	test_debug now, merge E into B &&
+	git checkout B &&
+	test_must_fail git merge E &&
+	test_debug force-resolve? &&
+	git add data &&
+	git commit -m F &&
+	git branch F &&
+
+
+	test_debug and merge D into C &&
+	git checkout C &&
+	test_must_fail git merge D &&
+	test_debug force-resolve? &&
+	git add data &&
+	git commit -m G &&
+	git branch G
+'
+
+test_expect_failure 'now, force a recursive merge between F and G' '
+	git merge F
+'
+
+test_done
-- 
1.6.2.1.493.g67cf3


--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]