From ad5a909cfbb07541e3e2548313043cc3f3a0918a Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Tue, 14 Mar 2017 09:39:37 +0100 Subject: [PATCH] patch_parse: fix parsing minimal trailing diff line In a diff, the shortest possible hunk with a modification (that is, no deletion) results from a file with only one line with a single character which is removed. Thus the following hunk @@ -1 +1 @@ -a + is the shortest valid hunk modifying a line. The function parsing the hunk body though assumes that there must always be at least 4 bytes present to make up a valid hunk, which is obviously wrong in this case. The absolute minimum number of bytes required for a modification is actually 2 bytes, that is the "+" and the following newline. Note: if there is no trailing newline, the assumption will not be offended as the diff will have a line "\ No trailing newline" at its end. This patch fixes the issue by lowering the amount of bytes required. --- src/patch_parse.c | 5 +++-- tests/diff/parse.c | 21 +++++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/src/patch_parse.c b/src/patch_parse.c index f5275947d..d993c0311 100644 --- a/src/patch_parse.c +++ b/src/patch_parse.c @@ -562,8 +562,9 @@ static int parse_hunk_body( int newlines = hunk->hunk.new_lines; for (; - ctx->remain_len > 4 && (oldlines || newlines) && - memcmp(ctx->line, "@@ -", 4) != 0; + ctx->remain_len > 1 && + (oldlines || newlines) && + (ctx->remain_len <= 4 || memcmp(ctx->line, "@@ -", 4) != 0); parse_advance_line(ctx)) { int origin; diff --git a/tests/diff/parse.c b/tests/diff/parse.c index b79b19e8e..35870594a 100644 --- a/tests/diff/parse.c +++ b/tests/diff/parse.c @@ -225,3 +225,24 @@ void test_diff_parse__foreach_works_with_parsed_patch(void) git_diff_free(diff); } + +void test_diff_parse__parsing_minimal_patch_succeeds(void) +{ + const char patch[] = + "diff --git a/obj1 b/obj2\n" + "index 1234567..7654321 10644\n" + "--- a/obj1\n" + "+++ b/obj2\n" + "@@ -1 +1 @@\n" + "-a\n" + "+\n"; + git_buf buf = GIT_BUF_INIT; + git_diff *diff; + + cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch))); + cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH)); + cl_assert_equal_s(patch, buf.ptr); + + git_diff_free(diff); + git_buf_free(&buf); +}