Skip to content

Commit 3efb988

Browse files
peffgitster
authored andcommitted
react to errors in xdi_diff
When we call into xdiff to perform a diff, we generally lose the return code completely. Typically by ignoring the return of our xdi_diff wrapper, but sometimes we even propagate that return value up and then ignore it later. This can lead to us silently producing incorrect diffs (e.g., "git log" might produce no output at all, not even a diff header, for a content-level diff). In practice this does not happen very often, because the typical reason for xdiff to report failure is that it malloc() failed (it uses straight malloc, and not our xmalloc wrapper). But it could also happen when xdiff triggers one our callbacks, which returns an error (e.g., outf() in builtin/rerere.c tries to report a write failure in this way). And the next patch also plans to add more failure modes. Let's notice an error return from xdiff and react appropriately. In most of the diff.c code, we can simply die(), which matches the surrounding code (e.g., that is what we do if we fail to load a file for diffing in the first place). This is not that elegant, but we are probably better off dying to let the user know there was a problem, rather than simply generating bogus output. We could also just die() directly in xdi_diff, but the callers typically have a bit more context, and can provide a better message (and if we do later decide to pass errors up, we're one step closer to doing so). There is one interesting case, which is in diff_grep(). Here if we cannot generate the diff, there is nothing to match, and we silently return "no hits". This is actually what the existing code does already, but we make it a little more explicit. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent ecad27c commit 3efb988

File tree

7 files changed

+41
-24
lines changed

7 files changed

+41
-24
lines changed

builtin/blame.c

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -972,7 +972,10 @@ static void pass_blame_to_parent(struct scoreboard *sb,
972972
fill_origin_blob(&sb->revs->diffopt, target, &file_o);
973973
num_get_patch++;
974974

975-
diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
975+
if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d))
976+
die("unable to generate diff (%s -> %s)",
977+
sha1_to_hex(parent->commit->object.sha1),
978+
sha1_to_hex(target->commit->object.sha1));
976979
/* The rest are the same as the parent */
977980
blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
978981
*d.dstq = NULL;
@@ -1118,7 +1121,9 @@ static void find_copy_in_blob(struct scoreboard *sb,
11181121
* file_p partially may match that image.
11191122
*/
11201123
memset(split, 0, sizeof(struct blame_entry [3]));
1121-
diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
1124+
if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d))
1125+
die("unable to generate diff (%s)",
1126+
sha1_to_hex(parent->commit->object.sha1));
11221127
/* remainder, if any, all match the preimage */
11231128
handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);
11241129
}

builtin/merge-tree.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,8 @@ static void show_diff(struct merge_list *entry)
118118
if (!dst.ptr)
119119
size = 0;
120120
dst.size = size;
121-
xdi_diff(&src, &dst, &xpp, &xecfg, &ecb);
121+
if (xdi_diff(&src, &dst, &xpp, &xecfg, &ecb))
122+
die("unable to generate diff");
122123
free(src.ptr);
123124
free(dst.ptr);
124125
}

builtin/rerere.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,10 @@ static int diff_two(const char *file1, const char *label1,
2929
xdemitconf_t xecfg;
3030
xdemitcb_t ecb;
3131
mmfile_t minus, plus;
32+
int ret;
3233

3334
if (read_mmfile(&minus, file1) || read_mmfile(&plus, file2))
34-
return 1;
35+
return -1;
3536

3637
printf("--- a/%s\n+++ b/%s\n", label1, label2);
3738
fflush(stdout);
@@ -40,11 +41,11 @@ static int diff_two(const char *file1, const char *label1,
4041
memset(&xecfg, 0, sizeof(xecfg));
4142
xecfg.ctxlen = 3;
4243
ecb.outf = outf;
43-
xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
44+
ret = xdi_diff(&minus, &plus, &xpp, &xecfg, &ecb);
4445

4546
free(minus.ptr);
4647
free(plus.ptr);
47-
return 0;
48+
return ret;
4849
}
4950

5051
int cmd_rerere(int argc, const char **argv, const char *prefix)
@@ -104,7 +105,8 @@ int cmd_rerere(int argc, const char **argv, const char *prefix)
104105
for (i = 0; i < merge_rr.nr; i++) {
105106
const char *path = merge_rr.items[i].string;
106107
const char *name = (const char *)merge_rr.items[i].util;
107-
diff_two(rerere_path(name, "preimage"), path, path, path);
108+
if (diff_two(rerere_path(name, "preimage"), path, path, path))
109+
die("unable to generate diff for %s", name);
108110
}
109111
else
110112
usage_with_options(rerere_usage, options);

combine-diff.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -419,8 +419,10 @@ static void combine_diff(const unsigned char *parent, unsigned int mode,
419419
state.num_parent = num_parent;
420420
state.n = n;
421421

422-
xdi_diff_outf(&parent_file, result_file, consume_line, &state,
423-
&xpp, &xecfg);
422+
if (xdi_diff_outf(&parent_file, result_file, consume_line, &state,
423+
&xpp, &xecfg))
424+
die("unable to generate combined diff for %s",
425+
sha1_to_hex(parent));
424426
free(parent_file.ptr);
425427

426428
/* Assign line numbers for this parent.

diff.c

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,8 +1002,9 @@ static void diff_words_show(struct diff_words_data *diff_words)
10021002
xpp.flags = 0;
10031003
/* as only the hunk header will be parsed, we need a 0-context */
10041004
xecfg.ctxlen = 0;
1005-
xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
1006-
&xpp, &xecfg);
1005+
if (xdi_diff_outf(&minus, &plus, fn_out_diff_words_aux, diff_words,
1006+
&xpp, &xecfg))
1007+
die("unable to generate word diff");
10071008
free(minus.ptr);
10081009
free(plus.ptr);
10091010
if (diff_words->current_plus != diff_words->plus.text.ptr +
@@ -2400,8 +2401,9 @@ static void builtin_diff(const char *name_a,
24002401
xecfg.ctxlen = strtoul(v, NULL, 10);
24012402
if (o->word_diff)
24022403
init_diff_words_data(&ecbdata, o, one, two);
2403-
xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
2404-
&xpp, &xecfg);
2404+
if (xdi_diff_outf(&mf1, &mf2, fn_out_consume, &ecbdata,
2405+
&xpp, &xecfg))
2406+
die("unable to generate diff for %s", one->path);
24052407
if (o->word_diff)
24062408
free_diff_words_data(&ecbdata);
24072409
if (textconv_one)
@@ -2478,8 +2480,9 @@ static void builtin_diffstat(const char *name_a, const char *name_b,
24782480
xpp.flags = o->xdl_opts;
24792481
xecfg.ctxlen = o->context;
24802482
xecfg.interhunkctxlen = o->interhunkcontext;
2481-
xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
2482-
&xpp, &xecfg);
2483+
if (xdi_diff_outf(&mf1, &mf2, diffstat_consume, diffstat,
2484+
&xpp, &xecfg))
2485+
die("unable to generate diffstat for %s", one->path);
24832486
}
24842487

24852488
diff_free_filespec_data(one);
@@ -2525,8 +2528,9 @@ static void builtin_checkdiff(const char *name_a, const char *name_b,
25252528
memset(&xecfg, 0, sizeof(xecfg));
25262529
xecfg.ctxlen = 1; /* at least one context line */
25272530
xpp.flags = 0;
2528-
xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
2529-
&xpp, &xecfg);
2531+
if (xdi_diff_outf(&mf1, &mf2, checkdiff_consume, &data,
2532+
&xpp, &xecfg))
2533+
die("unable to generate checkdiff for %s", one->path);
25302534

25312535
if (data.ws_rule & WS_BLANK_AT_EOF) {
25322536
struct emit_callback ecbdata;
@@ -4425,8 +4429,10 @@ static int diff_get_patch_id(struct diff_options *options, unsigned char *sha1)
44254429
xpp.flags = 0;
44264430
xecfg.ctxlen = 3;
44274431
xecfg.flags = 0;
4428-
xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
4429-
&xpp, &xecfg);
4432+
if (xdi_diff_outf(&mf1, &mf2, patch_id_consume, &data,
4433+
&xpp, &xecfg))
4434+
return error("unable to generate patch-id diff for %s",
4435+
p->one->path);
44304436
}
44314437

44324438
git_SHA1_Final(sha1, &ctx);

diffcore-pickaxe.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ static int diff_grep(mmfile_t *one, mmfile_t *two,
6262
ecbdata.hit = 0;
6363
xecfg.ctxlen = o->context;
6464
xecfg.interhunkctxlen = o->interhunkcontext;
65-
xdi_diff_outf(one, two, diffgrep_consume, &ecbdata,
66-
&xpp, &xecfg);
65+
if (xdi_diff_outf(one, two, diffgrep_consume, &ecbdata, &xpp, &xecfg))
66+
return 0;
6767
return ecbdata.hit;
6868
}
6969

line-log.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -325,7 +325,7 @@ static int collect_diff_cb(long start_a, long count_a,
325325
return 0;
326326
}
327327

328-
static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out)
328+
static int collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges *out)
329329
{
330330
struct collect_diff_cbdata cbdata = {NULL};
331331
xpparam_t xpp;
@@ -340,7 +340,7 @@ static void collect_diff(mmfile_t *parent, mmfile_t *target, struct diff_ranges
340340
xecfg.hunk_func = collect_diff_cb;
341341
memset(&ecb, 0, sizeof(ecb));
342342
ecb.priv = &cbdata;
343-
xdi_diff(parent, target, &xpp, &xecfg, &ecb);
343+
return xdi_diff(parent, target, &xpp, &xecfg, &ecb);
344344
}
345345

346346
/*
@@ -1030,7 +1030,8 @@ static int process_diff_filepair(struct rev_info *rev,
10301030
}
10311031

10321032
diff_ranges_init(&diff);
1033-
collect_diff(&file_parent, &file_target, &diff);
1033+
if (collect_diff(&file_parent, &file_target, &diff))
1034+
die("unable to generate diff for %s", pair->one->path);
10341035

10351036
/* NEEDSWORK should apply some heuristics to prevent mismatches */
10361037
free(rg->path);

0 commit comments

Comments
 (0)