Commit ae195a71 by Edward Thomson Committed by Edward Thomson

blame: guard xdiff calls for large files

parent 6c014bcc
...@@ -331,7 +331,7 @@ static int blame_internal(git_blame *blame) ...@@ -331,7 +331,7 @@ static int blame_internal(git_blame *blame)
blame->ent = ent; blame->ent = ent;
git_blame__like_git(blame, blame->options.flags); error = git_blame__like_git(blame, blame->options.flags);
cleanup: cleanup:
for (ent = blame->ent; ent; ) { for (ent = blame->ent; ent; ) {
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "commit.h" #include "commit.h"
#include "blob.h" #include "blob.h"
#include "xdiff/xinclude.h" #include "xdiff/xinclude.h"
#include "diff_xdiff.h"
/* /*
* Origin is refcounted and usually we keep the blob contents to be * 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) ...@@ -351,6 +352,13 @@ static int diff_hunks(mmfile_t file_a, mmfile_t file_b, void *cb_data)
ecb.priv = cb_data; ecb.priv = cb_data;
trim_common_tail(&file_a, &file_b, 0); 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); return xdl_diff(&file_a, &file_b, &xpp, &xecfg, &ecb);
} }
...@@ -379,7 +387,9 @@ static int pass_blame_to_parent( ...@@ -379,7 +387,9 @@ static int pass_blame_to_parent(
fill_origin_blob(parent, &file_p); fill_origin_blob(parent, &file_p);
fill_origin_blob(target, &file_o); 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 */ /* 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); blame_chunk(blame, d.tlno, d.plno, last_in_target, target, parent);
...@@ -477,12 +487,13 @@ static void pass_whole_blame(git_blame *blame, ...@@ -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; git_commit *commit = origin->commit;
int i, num_parents; int i, num_parents;
git_blame__origin *sg_buf[16]; git_blame__origin *sg_buf[16];
git_blame__origin *porigin, **sg_origin = sg_buf; git_blame__origin *porigin, **sg_origin = sg_buf;
int ret, error = 0;
num_parents = git_commit_parentcount(commit); num_parents = git_commit_parentcount(commit);
if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit)) if (!git_oid_cmp(git_commit_id(commit), &blame->options.oldest_commit))
...@@ -540,9 +551,14 @@ static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt ...@@ -540,9 +551,14 @@ static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt
origin_incref(porigin); origin_incref(porigin);
origin->previous = 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; goto finish;
} }
}
/* TODO: optionally find moves in parents' files */ /* TODO: optionally find moves in parents' files */
...@@ -554,7 +570,7 @@ finish: ...@@ -554,7 +570,7 @@ finish:
origin_decref(sg_origin[i]); origin_decref(sg_origin[i]);
if (sg_origin != sg_buf) if (sg_origin != sg_buf)
git__free(sg_origin); git__free(sg_origin);
return; return error;
} }
/* /*
...@@ -583,7 +599,7 @@ static void coalesce(git_blame *blame) ...@@ -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) { while (true) {
git_blame__entry *ent; git_blame__entry *ent;
...@@ -594,11 +610,13 @@ void git_blame__like_git(git_blame *blame, uint32_t opt) ...@@ -594,11 +610,13 @@ void git_blame__like_git(git_blame *blame, uint32_t opt)
if (!ent->guilty) if (!ent->guilty)
suspect = ent->suspect; suspect = ent->suspect;
if (!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. */ /* We'll use this suspect later in the loop, so hold on to it for now. */
origin_incref(suspect); origin_incref(suspect);
pass_blame(blame, suspect, opt);
if (pass_blame(blame, suspect, opt) < 0)
return -1;
/* Take responsibility for the remaining entries */ /* Take responsibility for the remaining entries */
for (ent = blame->ent; ent; ent = ent->next) { for (ent = blame->ent; ent; ent = ent->next) {
...@@ -613,6 +631,8 @@ void git_blame__like_git(git_blame *blame, uint32_t opt) ...@@ -613,6 +631,8 @@ void git_blame__like_git(git_blame *blame, uint32_t opt)
} }
coalesce(blame); coalesce(blame);
return 0;
} }
void git_blame__free_entry(git_blame__entry *ent) void git_blame__free_entry(git_blame__entry *ent)
......
...@@ -15,6 +15,6 @@ int git_blame__get_origin( ...@@ -15,6 +15,6 @@ int git_blame__get_origin(
git_commit *commit, git_commit *commit,
const char *path); const char *path);
void git_blame__free_entry(git_blame__entry *ent); void git_blame__free_entry(git_blame__entry *ent);
void git_blame__like_git(git_blame *sb, uint32_t flags); int git_blame__like_git(git_blame *sb, uint32_t flags);
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment