apply: check git diffs for mutually exclusive header lines

A file can either be added, removed, copied, or renamed, but no two of
these actions can be done by the same patch.  Some of these combinations
provoke error messages due to missing file names, and some are only
caught by an assertion.  Check git patches already as they are parsed
and report conflicting lines on sight.

Found by Vegard Nossum using AFL.

Reported-by: Vegard Nossum <vegard.nossum@oracle.com>
Signed-off-by: Rene Scharfe <l.s.r@web.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
René Scharfe 2017-06-27 19:03:39 +02:00 committed by Junio C Hamano
parent 44e5471a8d
commit d70e9c5c8c
2 changed files with 33 additions and 0 deletions

15
apply.c
View File

@ -210,6 +210,7 @@ struct patch {
unsigned ws_rule;
int lines_added, lines_deleted;
int score;
int extension_linenr; /* first line specifying delete/new/rename/copy */
unsigned int is_toplevel_relative:1;
unsigned int inaccurate_eof:1;
unsigned int is_binary:1;
@ -1329,6 +1330,18 @@ static char *git_header_name(struct apply_state *state,
}
}
static int check_header_line(struct apply_state *state, struct patch *patch)
{
int extensions = (patch->is_delete == 1) + (patch->is_new == 1) +
(patch->is_rename == 1) + (patch->is_copy == 1);
if (extensions > 1)
return error(_("inconsistent header lines %d and %d"),
patch->extension_linenr, state->linenr);
if (extensions && !patch->extension_linenr)
patch->extension_linenr = state->linenr;
return 0;
}
/* Verify that we recognize the lines following a git header */
static int parse_git_header(struct apply_state *state,
const char *line,
@ -1395,6 +1408,8 @@ static int parse_git_header(struct apply_state *state,
res = p->fn(state, line + oplen, patch);
if (res < 0)
return -1;
if (check_header_line(state, patch))
return -1;
if (res > 0)
return offset;
break;

View File

@ -29,4 +29,22 @@ test_expect_success 'apply exits non-zero with no-op patch' '
test_must_fail git apply --check input
'
test_expect_success 'invalid combination: create and copy' '
test_must_fail git apply --check - <<-\EOF
diff --git a/1 b/2
new file mode 100644
copy from 1
copy to 2
EOF
'
test_expect_success 'invalid combination: create and rename' '
test_must_fail git apply --check - <<-\EOF
diff --git a/1 b/2
new file mode 100644
rename from 1
rename to 2
EOF
'
test_done