Skip to content

Commit

Permalink
range-diff: don't segfault with mode-only changes
Browse files Browse the repository at this point in the history
In ef283b3 ("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 <[email protected]>
Signed-off-by: Thomas Gummerer <[email protected]>
Acked-by: Johannes Schindelin <[email protected]>
Signed-off-by: Junio C Hamano <[email protected]>
  • Loading branch information
tgummerer authored and gitster committed Oct 9, 2019
1 parent 499352c commit 2b6a9b1
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 22 deletions.
43 changes: 22 additions & 21 deletions apply.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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;
}
Expand Down
40 changes: 40 additions & 0 deletions t/t3206-range-diff.sh
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,46 @@ test_expect_success 'renamed file' '
test_cmp expected actual
'

test_expect_success 'file with mode only change' '
git range-diff --no-color --submodule=log topic...mode-only-change >actual &&
sed s/Z/\ /g >expected <<-EOF &&
1: fccce22 ! 1: 4d39cb3 s/4/A/
@@ Metadata
ZAuthor: Thomas Rast <[email protected]>
Z
Z ## Commit message ##
- s/4/A/
+ s/4/A/ + add other-file
Z
Z ## file ##
Z@@
@@ file
Z A
Z 6
Z 7
+
+ ## other-file (new) ##
2: 147e64e ! 2: 26c107f s/11/B/
@@ Metadata
ZAuthor: Thomas Rast <[email protected]>
Z
Z ## Commit message ##
- s/11/B/
+ s/11/B/ + mode change other-file
Z
Z ## file ##
Z@@ file: A
@@ file: A
Z 12
Z 13
Z 14
+
+ ## other-file (mode change 100644 => 100755) ##
3: a63e992 = 3: 4c1e0f5 s/12/B/
EOF
test_cmp expected actual
'

test_expect_success 'file added and later removed' '
git range-diff --no-color --submodule=log topic...added-removed >actual &&
sed s/Z/\ /g >expected <<-EOF &&
Expand Down
31 changes: 30 additions & 1 deletion t/t3206/history.export
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ A
19
20

commit refs/heads/topic
commit refs/heads/mode-only-change
mark :4
author Thomas Rast <[email protected]> 1374485014 +0200
committer Thomas Rast <[email protected]> 1374485014 +0200
Expand Down Expand Up @@ -678,3 +678,32 @@ s/12/B/
from :55
M 100644 :9 renamed-file

commit refs/heads/mode-only-change
mark :57
author Thomas Rast <[email protected]> 1374485024 +0200
committer Thomas Gummerer <[email protected]> 1570473767 +0100
data 24
s/4/A/ + add other-file
from :4
M 100644 :5 file
M 100644 :49 other-file

commit refs/heads/mode-only-change
mark :58
author Thomas Rast <[email protected]> 1374485036 +0200
committer Thomas Gummerer <[email protected]> 1570473768 +0100
data 33
s/11/B/ + mode change other-file
from :57
M 100644 :7 file
M 100755 :49 other-file

commit refs/heads/mode-only-change
mark :59
author Thomas Rast <[email protected]> 1374485044 +0200
committer Thomas Gummerer <[email protected]> 1570473768 +0100
data 8
s/12/B/
from :58
M 100644 :9 file

0 comments on commit 2b6a9b1

Please sign in to comment.