summaryrefslogtreecommitdiff
path: root/apply.c
diff options
context:
space:
mode:
authorThomas Gummerer <t.gummerer@gmail.com>2019-10-08 17:38:43 (GMT)
committerJunio C Hamano <gitster@pobox.com>2019-10-09 01:41:11 (GMT)
commit2b6a9b13ca4a687aeb0cad5f32e49711b3e67aaa (patch)
treebf3c67db6ca8048ab24be48ffaa4adf3868d566c /apply.c
parent499352c2adf9c038ec3469d73590b1c55b6a343b (diff)
downloadgit-2b6a9b13ca4a687aeb0cad5f32e49711b3e67aaa.zip
git-2b6a9b13ca4a687aeb0cad5f32e49711b3e67aaa.tar.gz
git-2b6a9b13ca4a687aeb0cad5f32e49711b3e67aaa.tar.bz2
range-diff: don't segfault with mode-only changes
In ef283b3699 ("apply: make parse_git_diff_header public", 2019-07-11) the 'parse_git_diff_header' function was made public and useable by callers outside of apply.c. However it was missed that its (then) only caller, 'find_header' did some error handling, and completing 'struct patch' appropriately. range-diff then started using this function, and tried to handle this appropriately itself, but fell short in some cases. This in turn would lead to range-diff segfaulting when there are mode-only changes in a range. Move the error handling and completing of the struct into the 'parse_git_diff_header' function, so other callers can take advantage of it. This fixes the segfault in 'git range-diff'. Reported-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de> Signed-off-by: Thomas Gummerer <t.gummerer@gmail.com> Acked-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'apply.c')
-rw-r--r--apply.c43
1 files changed, 22 insertions, 21 deletions
diff --git a/apply.c b/apply.c
index cde9536..5f06a14 100644
--- a/apply.c
+++ b/apply.c
@@ -1361,11 +1361,32 @@ int parse_git_diff_header(struct strbuf *root,
if (check_header_line(*linenr, patch))
return -1;
if (res > 0)
- return offset;
+ goto done;
break;
}
}
+done:
+ if (!patch->old_name && !patch->new_name) {
+ if (!patch->def_name) {
+ error(Q_("git diff header lacks filename information when removing "
+ "%d leading pathname component (line %d)",
+ "git diff header lacks filename information when removing "
+ "%d leading pathname components (line %d)",
+ parse_hdr_state.p_value),
+ parse_hdr_state.p_value, *linenr);
+ return -128;
+ }
+ patch->old_name = xstrdup(patch->def_name);
+ patch->new_name = xstrdup(patch->def_name);
+ }
+ if ((!patch->new_name && !patch->is_delete) ||
+ (!patch->old_name && !patch->is_new)) {
+ error(_("git diff header lacks filename information "
+ "(line %d)"), *linenr);
+ return -128;
+ }
+ patch->is_toplevel_relative = 1;
return offset;
}
@@ -1546,26 +1567,6 @@ static int find_header(struct apply_state *state,
return -128;
if (git_hdr_len <= len)
continue;
- if (!patch->old_name && !patch->new_name) {
- if (!patch->def_name) {
- error(Q_("git diff header lacks filename information when removing "
- "%d leading pathname component (line %d)",
- "git diff header lacks filename information when removing "
- "%d leading pathname components (line %d)",
- state->p_value),
- state->p_value, state->linenr);
- return -128;
- }
- patch->old_name = xstrdup(patch->def_name);
- patch->new_name = xstrdup(patch->def_name);
- }
- if ((!patch->new_name && !patch->is_delete) ||
- (!patch->old_name && !patch->is_new)) {
- error(_("git diff header lacks filename information "
- "(line %d)"), state->linenr);
- return -128;
- }
- patch->is_toplevel_relative = 1;
*hdrsize = git_hdr_len;
return offset;
}