summaryrefslogtreecommitdiff
path: root/src/blame_git.c
diff options
context:
space:
mode:
authorEdward Thomson <ethomson@microsoft.com>2015-09-29 12:46:41 -0400
committerEdward Thomson <ethomson@edwardthomson.com>2015-10-05 22:59:53 +0200
commitae195a71ae898b7d5d61943f24f31d97065a87c6 (patch)
treefe774e6e29efde5bd872c6221fc2fdf92aac5b8c /src/blame_git.c
parent6c014bcc54fb9923490f9af917dc43e3661e5782 (diff)
downloadlibgit2-ae195a71ae898b7d5d61943f24f31d97065a87c6.tar.gz
blame: guard xdiff calls for large files
Diffstat (limited to 'src/blame_git.c')
-rw-r--r--src/blame_git.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/src/blame_git.c b/src/blame_git.c
index f481426aa..67bae2384 100644
--- a/src/blame_git.c
+++ b/src/blame_git.c
@@ -9,6 +9,7 @@
#include "commit.h"
#include "blob.h"
#include "xdiff/xinclude.h"
+#include "diff_xdiff.h"
/*
* Origin is refcounted and usually we keep the blob contents to be
@@ -351,6 +352,13 @@ static int diff_hunks(mmfile_t file_a, mmfile_t file_b, void *cb_data)
ecb.priv = cb_data;
trim_common_tail(&file_a, &file_b, 0);
+
+ if (file_a.size > GIT_XDIFF_MAX_SIZE ||
+ file_b.size > GIT_XDIFF_MAX_SIZE) {
+ giterr_set(GITERR_INVALID, "file too large to blame");
+ return -1;
+ }
+
return xdl_diff(&file_a, &file_b, &xpp, &xecfg, &ecb);
}
@@ -379,7 +387,9 @@ static int pass_blame_to_parent(
fill_origin_blob(parent, &file_p);
fill_origin_blob(target, &file_o);
- diff_hunks(file_p, file_o, &d);
+ if (diff_hunks(file_p, file_o, &d) < 0)
+ return -1;
+
/* The reset (i.e. anything after tlno) are the same as the parent */
blame_chunk(blame, d.tlno, d.plno, last_in_target, target, parent);
@@ -477,12 +487,13 @@ static void pass_whole_blame(git_blame *blame,
}
}
-static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
+static int pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt)
{
git_commit *commit = origin->commit;
int i, num_parents;
git_blame__origin *sg_buf[16];
git_blame__origin *porigin, **sg_origin = sg_buf;
+ int ret, error = 0;
num_parents = git_commit_parentcount(commit);
if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit))
@@ -540,8 +551,13 @@ static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt
origin_incref(porigin);
origin->previous = porigin;
}
- if (pass_blame_to_parent(blame, origin, porigin))
+
+ if ((ret = pass_blame_to_parent(blame, origin, porigin)) != 0) {
+ if (ret < 0)
+ error = -1;
+
goto finish;
+ }
}
/* TODO: optionally find moves in parents' files */
@@ -554,7 +570,7 @@ finish:
origin_decref(sg_origin[i]);
if (sg_origin != sg_buf)
git__free(sg_origin);
- return;
+ return error;
}
/*
@@ -583,7 +599,7 @@ static void coalesce(git_blame *blame)
}
}
-void git_blame__like_git(git_blame *blame, uint32_t opt)
+int git_blame__like_git(git_blame *blame, uint32_t opt)
{
while (true) {
git_blame__entry *ent;
@@ -594,11 +610,13 @@ void git_blame__like_git(git_blame *blame, uint32_t opt)
if (!ent->guilty)
suspect = ent->suspect;
if (!suspect)
- return; /* all done */
+ return 0; /* all done */
/* We'll use this suspect later in the loop, so hold on to it for now. */
origin_incref(suspect);
- pass_blame(blame, suspect, opt);
+
+ if (pass_blame(blame, suspect, opt) < 0)
+ return -1;
/* Take responsibility for the remaining entries */
for (ent = blame->ent; ent; ent = ent->next) {
@@ -613,6 +631,8 @@ void git_blame__like_git(git_blame *blame, uint32_t opt)
}
coalesce(blame);
+
+ return 0;
}
void git_blame__free_entry(git_blame__entry *ent)