git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH] Fix segfault in merge-recursive

From
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
May 8, 2009, 20:30 UTC
Message-ID
<alpine.DEB.1.00.0905082229520.4601@intel-tinevez-2-302>
In-Reply-To
<alpine.DEB.2.00.0905072131470.30999@narbuckle.genericorp.net>

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@gmx.de>
---
	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
Previous: Dave ONext: Dave O
Message 4 of 13 in “Segfault during merge”
  1. Dave OMay 7, 2009
  2. Johannes SchindelinMay 7, 2009
  3. Dave OMay 8, 2009
  4. Fix segfault in merge-recursiveJohannes Schindelin, May 8, 2009
  5. Dave OMay 8, 2009
  6. Johannes SchindelinMay 8, 2009
  7. Dave OMay 8, 2009
  8. Don't update index while recursing (was Re: Segfault during merge)Dave O, May 9, 2009
  9. Johannes SchindelinMay 9, 2009
  10. Junio C HamanoMay 9, 2009
  11. Junio C HamanoMay 8, 2009
  12. Johannes SchindelinMay 9, 2009
  13. Jakub NarebskiMay 7, 2009

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.