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

[PATCH] rerere forget: do not segfault if not all stages are present

From
Johannes Sixt <j6t@kdbg.org>
Date
Apr 4, 2013, 18:41 UTC
Message-ID
<515DC967.3060108@kdbg.org>

The loop that fills in the buffers that are later passed to the merge driver exits early when not all stages of a path are present in the index. But since the buffer pointers are not initialized in advance, the subsequent accesses are undefined.

Initialize buffer pointers in advance to avoid undefined behavior later.

That is not sufficient, though, to get correct operation of handle_cache(). The function replays a conflicted merge to extract the part inside the conflict markers. As written, the loop exits early when a stage is missing. Consequently, the buffers for later stages that would be present in the index are not filled in and the merge is replayed with incomplete data.

Fix it by investigating all stages of the given path.
Signed-off-by: Johannes Sixt <j6t@kdbg.org>
---
 This patch conflicts trivially with js/rerere-forget-protect-against-NUL
 (both add a test case at the end).
 rerere.c                  | 15 +++++++--------
 t/t2030-unresolve-info.sh | 13 +++++++++++++
 2 files changed, 20 insertions(+), 8 deletions(-)
diff --git a/rerere.c b/rerere.c
index a6a5cd5..3d22cd2 100644
--- a/rerere.c
+++ b/rerere.c
@@ -295,7 +295,7 @@ static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_)
 
 static int handle_cache(const char *path, unsigned char *sha1, const char *output)
 {
-	mmfile_t mmfile[3];
+	mmfile_t mmfile[3] = {{NULL}};
 	mmbuffer_t result = {NULL, 0};
 	struct cache_entry *ce;
 	int pos, len, i, hunk_no;
@@ -314,17 +314,16 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
 	for (i = 0; i < 3; i++) {
 		enum object_type type;
 		unsigned long size;
+		int j;
 
-		mmfile[i].size = 0;
-		mmfile[i].ptr = NULL;
 		if (active_nr <= pos)
 			break;
 		ce = active_cache[pos++];
-		if (ce_namelen(ce) != len || memcmp(ce->name, path, len)
-		    || ce_stage(ce) != i + 1)
-			break;
-		mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size);
-		mmfile[i].size = size;
+		if (ce_namelen(ce) != len || memcmp(ce->name, path, len))
+			continue;
+		j = ce_stage(ce) - 1;
+		mmfile[j].ptr = read_sha1_file(ce->sha1, &type, &size);
+		mmfile[j].size = size;
 	}
 	for (i = 0; i < 3; i++) {
 		if (!mmfile[i].ptr && !mmfile[i].size)
diff --git a/t/t2030-unresolve-info.sh b/t/t2030-unresolve-info.sh
index f262065..c0610b9 100755
--- a/t/t2030-unresolve-info.sh
+++ b/t/t2030-unresolve-info.sh
@@ -50,8 +50,11 @@ test_expect_success setup '
 	test_commit second fi/le second &&
 	git checkout side &&
 	test_commit third fi/le third &&
+	git branch add-add &&
 	git checkout another &&
 	test_commit fourth fi/le fourth &&
+	git checkout add-add &&
+	test_commit fifth add-differently &&
 	git checkout master
 '
 
@@ -167,4 +170,14 @@ test_expect_success 'rerere and rerere forget (subdirectory)' '
 	test_cmp expect actual
 '
 
+test_expect_success 'rerere forget (add-add conflict)' '
+	git checkout -f master &&
+	echo master >add-differently &&
+	git add add-differently &&
+	git commit -m "add differently" &&
+	test_must_fail git merge fifth &&
+	git rerere forget add-differently 2>actual &&
+	test_i18ngrep "no remembered" actual
+'
+
 test_done
-- 
1.8.2.384.g92e0289
Message 1 of 1 in “rerere forget: do not segfault if not all stages are present”
  1. rerere forget: do not segfault if not all stages are presentJohannes Sixt, Apr 4, 2013

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.