path: root/builtin/blame.c
diff options
authorJeff King <>2015-09-24 23:12:23 (GMT)
committerJunio C Hamano <>2015-09-28 21:57:10 (GMT)
commit3efb988098858bf6b974b1e673a190f9d2965d1d (patch)
tree9fcbccbbb49f0e7ce19beb85e17c4e60a3ba2b5c /builtin/blame.c
parentecad27cf98c391d5cfdc26ce0e442e02347baad0 (diff)
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 <> Signed-off-by: Junio C Hamano <>
Diffstat (limited to 'builtin/blame.c')
1 files changed, 7 insertions, 2 deletions
diff --git a/builtin/blame.c b/builtin/blame.c
index 2b1f9dd..66b4fbf 100644
--- a/builtin/blame.c
+++ b/builtin/blame.c
@@ -972,7 +972,10 @@ static void pass_blame_to_parent(struct scoreboard *sb,
fill_origin_blob(&sb->revs->diffopt, target, &file_o);
- diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d);
+ if (diff_hunks(&file_p, &file_o, 0, blame_chunk_cb, &d))
+ die("unable to generate diff (%s -> %s)",
+ sha1_to_hex(parent->commit->object.sha1),
+ sha1_to_hex(target->commit->object.sha1));
/* The rest are the same as the parent */
blame_chunk(&d.dstq, &d.srcq, INT_MAX, d.offset, INT_MAX, parent);
*d.dstq = NULL;
@@ -1118,7 +1121,9 @@ static void find_copy_in_blob(struct scoreboard *sb,
* file_p partially may match that image.
memset(split, 0, sizeof(struct blame_entry [3]));
- diff_hunks(file_p, &file_o, 1, handle_split_cb, &d);
+ if (diff_hunks(file_p, &file_o, 1, handle_split_cb, &d))
+ die("unable to generate diff (%s)",
+ sha1_to_hex(parent->commit->object.sha1));
/* remainder, if any, all match the preimage */
handle_split(sb, ent, d.tlno, d.plno, ent->num_lines, parent, split);