Skip to content

Commit

Permalink
rerere forget: do not segfault if not all stages are present
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
j6t authored and gitster committed Apr 4, 2013
1 parent 53d8afa commit b9e31f5
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 8 deletions.
15 changes: 7 additions & 8 deletions rerere.c
Expand Up @@ -297,7 +297,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;
Expand All @@ -316,17 +316,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)
Expand Down
13 changes: 13 additions & 0 deletions t/t2030-unresolve-info.sh
Expand Up @@ -54,8 +54,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
'

Expand Down Expand Up @@ -179,4 +182,14 @@ test_expect_success 'rerere forget (binary)' '
git rerere forget binary
'

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

0 comments on commit b9e31f5

Please sign in to comment.