Skip to content

Commit ad5a909

Browse files
committed
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.
1 parent 62a2fc0 commit ad5a909

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

src/patch_parse.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -562,8 +562,9 @@ static int parse_hunk_body(
562562
int newlines = hunk->hunk.new_lines;
563563

564564
for (;
565-
ctx->remain_len > 4 && (oldlines || newlines) &&
566-
memcmp(ctx->line, "@@ -", 4) != 0;
565+
ctx->remain_len > 1 &&
566+
(oldlines || newlines) &&
567+
(ctx->remain_len <= 4 || memcmp(ctx->line, "@@ -", 4) != 0);
567568
parse_advance_line(ctx)) {
568569

569570
int origin;

tests/diff/parse.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,3 +225,24 @@ void test_diff_parse__foreach_works_with_parsed_patch(void)
225225

226226
git_diff_free(diff);
227227
}
228+
229+
void test_diff_parse__parsing_minimal_patch_succeeds(void)
230+
{
231+
const char patch[] =
232+
"diff --git a/obj1 b/obj2\n"
233+
"index 1234567..7654321 10644\n"
234+
"--- a/obj1\n"
235+
"+++ b/obj2\n"
236+
"@@ -1 +1 @@\n"
237+
"-a\n"
238+
"+\n";
239+
git_buf buf = GIT_BUF_INIT;
240+
git_diff *diff;
241+
242+
cl_git_pass(git_diff_from_buffer(&diff, patch, strlen(patch)));
243+
cl_git_pass(git_diff_to_buf(&buf, diff, GIT_DIFF_FORMAT_PATCH));
244+
cl_assert_equal_s(patch, buf.ptr);
245+
246+
git_diff_free(diff);
247+
git_buf_free(&buf);
248+
}

0 commit comments

Comments
 (0)