@matheusbsbs / matheus-bagliano / commits / 2179870803
Fork 0

combined diff: correctly handle truncated file

Consider an evil merge of two commits A and B, both of which have a file 'foo', but the merge result does not have that file. The combined-diff code learned in 4462731 (combine-diff: do not punt on removed or added files., 2006-02-06) to concisely show only the removal, since that is the evil part and the previous contents are presumably uninteresting. However, to diagnose an empty merge result, it overloaded the variable that holds the file's length. This means that the check also triggers for truncated files. Consequently, such files were not shown in the diff at all despite the merge being clearly evil. Fix this by adding a new variable that distinguishes whether the file was deleted (which is the case 4462731 handled) or truncated. In the truncated case, we show the full combined diff again, which is rather spammy but at least does not hide the evilness. Reported-by: David Martínez Martí <desarrollo@gestiweb.com> Signed-off-by: Thomas Rast <trast@student.ethz.ch> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Thomas Rast committed Apr 15, 2010 at 14:59 UTC 21798708031ed808cb77232e771e20d3146cf9c8
2 files changed +16 -6
combine-diff.c
+8 -6
@@ -204,7 +204,7 @@ static void consume_line(void *state_, char *line, unsigned long len)
204 static void combine_diff(const unsigned char *parent, unsigned int mode,
205 mmfile_t *result_file,
206 struct sline *sline, unsigned int cnt, int n,
207 - int num_parent)
207 + int num_parent, int result_deleted)
208 {
209 unsigned int p_lno, lno;
210 unsigned long nmask = (1UL << n);
@@ -215,7 +215,7 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
215 struct combine_diff_state state;
216 unsigned long sz;
217
218 - if (!cnt)
218 + if (result_deleted)
219 return; /* result deleted */
220
221 parent_file.ptr = grab_blob(parent, mode, &sz);
@@ -517,7 +517,7 @@ static void show_line_to_eol(const char *line, int len, const char *reset)
517 }
518
519 static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
520 - int use_color)
520 + int use_color, int result_deleted)
521 {
522 unsigned long mark = (1UL<<num_parent);
523 unsigned long no_pre_delete = (2UL<<num_parent);
@@ -530,7 +530,7 @@ static void dump_sline(struct sline *sline, unsigned long cnt, int num_parent,
530 const char *c_plain = diff_get_color(use_color, DIFF_PLAIN);
531 const char *c_reset = diff_get_color(use_color, DIFF_RESET);
532
533 - if (!cnt)
533 + if (result_deleted)
534 return; /* result deleted */
535
536 while (1) {
@@ -687,6 +687,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
687 {
688 struct diff_options *opt = &rev->diffopt;
689 unsigned long result_size, cnt, lno;
690 + int result_deleted = 0;
691 char *result, *cp;
692 struct sline *sline; /* survived lines */
693 int mode_differs = 0;
@@ -767,6 +768,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
768 }
769 else {
770 deleted_file:
771 + result_deleted = 1;
772 result_size = 0;
773 elem->mode = 0;
774 result = xcalloc(1, 1);
@@ -823,7 +825,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
825 combine_diff(elem->parent[i].sha1,
826 elem->parent[i].mode,
827 &result_file, sline,
826 - cnt, i, num_parent);
828 + cnt, i, num_parent, result_deleted);
829 if (elem->parent[i].mode != elem->mode)
830 mode_differs = 1;
831 }
@@ -889,7 +891,7 @@ static void show_patch_diff(struct combine_diff_path *elem, int num_parent,
891 dump_quoted_path("+++ ", b_prefix, elem->path,
892 c_meta, c_reset);
893 dump_sline(sline, cnt, num_parent,
892 - DIFF_OPT_TST(opt, COLOR_DIFF));
894 + DIFF_OPT_TST(opt, COLOR_DIFF), result_deleted);
895 }
896 free(result);
897
t/t4038-diff-combined.sh
+8
@@ -81,4 +81,12 @@ test_expect_success 'check combined output (2)' '
81 verify_helper sidesansone
82 '
83
84 +test_expect_success 'diagnose truncated file' '
85 + >file &&
86 + git add file &&
87 + git commit --amend -C HEAD &&
88 + git show >out &&
89 + grep "diff --cc file" out
90 +'
91 +
92 test_done