Skip to content

Commit b9e31f5

Browse files
j6tgitster
authored andcommitted
rerere forget: do not segfault if not all stages are present
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 53d8afa commit b9e31f5

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

rerere.c

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ static int rerere_mem_getline(struct strbuf *sb, struct rerere_io *io_)
297297

298298
static int handle_cache(const char *path, unsigned char *sha1, const char *output)
299299
{
300-
mmfile_t mmfile[3];
300+
mmfile_t mmfile[3] = {{NULL}};
301301
mmbuffer_t result = {NULL, 0};
302302
struct cache_entry *ce;
303303
int pos, len, i, hunk_no;
@@ -316,17 +316,16 @@ static int handle_cache(const char *path, unsigned char *sha1, const char *outpu
316316
for (i = 0; i < 3; i++) {
317317
enum object_type type;
318318
unsigned long size;
319+
int j;
319320

320-
mmfile[i].size = 0;
321-
mmfile[i].ptr = NULL;
322321
if (active_nr <= pos)
323322
break;
324323
ce = active_cache[pos++];
325-
if (ce_namelen(ce) != len || memcmp(ce->name, path, len)
326-
|| ce_stage(ce) != i + 1)
327-
break;
328-
mmfile[i].ptr = read_sha1_file(ce->sha1, &type, &size);
329-
mmfile[i].size = size;
324+
if (ce_namelen(ce) != len || memcmp(ce->name, path, len))
325+
continue;
326+
j = ce_stage(ce) - 1;
327+
mmfile[j].ptr = read_sha1_file(ce->sha1, &type, &size);
328+
mmfile[j].size = size;
330329
}
331330
for (i = 0; i < 3; i++) {
332331
if (!mmfile[i].ptr && !mmfile[i].size)

t/t2030-unresolve-info.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,11 @@ test_expect_success setup '
5454
test_commit second fi/le second &&
5555
git checkout side &&
5656
test_commit third fi/le third &&
57+
git branch add-add &&
5758
git checkout another &&
5859
test_commit fourth fi/le fourth &&
60+
git checkout add-add &&
61+
test_commit fifth add-differently &&
5962
git checkout master
6063
'
6164

@@ -179,4 +182,14 @@ test_expect_success 'rerere forget (binary)' '
179182
git rerere forget binary
180183
'
181184

185+
test_expect_success 'rerere forget (add-add conflict)' '
186+
git checkout -f master &&
187+
echo master >add-differently &&
188+
git add add-differently &&
189+
git commit -m "add differently" &&
190+
test_must_fail git merge fifth &&
191+
git rerere forget add-differently 2>actual &&
192+
test_i18ngrep "no remembered" actual
193+
'
194+
182195
test_done

0 commit comments

Comments
 (0)