summaryrefslogtreecommitdiffstats
path: root/rerere.c
diff options
context:
space:
mode:
authorThomas Gummerer <t.gummerer@gmail.com>2018-08-05 18:20:32 +0100
committerJunio C Hamano <gitster@pobox.com>2018-08-06 13:22:35 -0700
commit93406a282f404fd9f736e96ae27cc6e2e5eb3cf1 (patch)
tree1d235058224d8ae9112e38108d0c2d7a3d84c7f5 /rerere.c
parentfb90dca34c498ac1f922d579c202b4723e87455a (diff)
downloadgit-93406a282f404fd9f736e96ae27cc6e2e5eb3cf1.tar.gz
git-93406a282f404fd9f736e96ae27cc6e2e5eb3cf1.tar.xz
rerere: fix crash with files rerere can't handle
Currently when a user does a conflict resolution and ends it (in any way that calls 'git rerere' again) with a file 'rerere' can't handle, subsequent rerere operations that are interested in that path, such as 'rerere clear' or 'rerere forget <path>' will fail, or even worse in the case of 'rerere clear' segfault. Such states include nested conflicts, or a conflict marker that doesn't have any match. This is because 'git rerere' calculates a conflict file and writes it to the MERGE_RR file. When the user then changes the file in any way rerere can't handle, and then calls 'git rerere' on it again to record the conflict resolution, the handle_file function fails, and removes the 'preimage' file in the rr-cache in the process, while leaving the ID in the MERGE_RR file. Now when 'rerere clear' is run, it reads the ID from the MERGE_RR file, however the 'fit_variant' function for the ID is never called as the 'preimage' file does not exist anymore. This means 'collection->status' in 'has_rerere_resolution' is NULL, and the command will crash. To fix this, remove the rerere ID from the MERGE_RR file in the case when we can't handle it, just after the 'preimage' file was removed and remove the corresponding variant from .git/rr-cache/. Removing it unconditionally is fine here, because if the user would have resolved the conflict and ran rerere, the entry would no longer be in the MERGE_RR file, so we wouldn't have this problem in the first place, while if the conflict was not resolved. Currently there is nothing left in this folder, as the 'preimage' was already deleted by the 'handle_file' function, so 'remove_variant' is a no-op. Still call the function, to make sure we clean everything up, in case we add some other files corresponding to a variant in the future. Note that other variants that have the same conflict ID will not be touched. Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'rerere.c')
-rw-r--r--rerere.c12
1 files changed, 7 insertions, 5 deletions
diff --git a/rerere.c b/rerere.c
index da1ab5402..895ad80c0 100644
--- a/rerere.c
+++ b/rerere.c
@@ -823,10 +823,7 @@ static int do_plain_rerere(struct string_list *rr, int fd)
struct rerere_id *id;
unsigned char sha1[20];
const char *path = conflict.items[i].string;
- int ret;
-
- if (string_list_has_string(rr, path))
- continue;
+ int ret, has_string;
/*
* Ask handle_file() to scan and assign a
@@ -834,7 +831,12 @@ static int do_plain_rerere(struct string_list *rr, int fd)
* yet.
*/
ret = handle_file(path, sha1, NULL);
- if (ret < 1)
+ has_string = string_list_has_string(rr, path);
+ if (ret < 0 && has_string) {
+ remove_variant(string_list_lookup(rr, path)->util);
+ string_list_remove(rr, path, 1);
+ }
+ if (ret < 1 || has_string)
continue;
id = new_rerere_id(sha1);