0.23 xdiff by ethomson · Pull Request #3452 · libgit2/libgit2 · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions include/git2/version.h
2 changes: 1 addition & 1 deletion src/blame.c
Original file line number Diff line number Diff line change
Expand Up @@ -331,7 +331,7 @@ static int blame_internal(git_blame *blame)

blame->ent = ent;

git_blame__like_git(blame, blame->options.flags);
error = git_blame__like_git(blame, blame->options.flags);

cleanup:
for (ent = blame->ent; ent; ) {
Expand Down
34 changes: 27 additions & 7 deletions src/blame_git.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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);
}

Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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))
Expand Down Expand Up @@ -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 */
Expand All @@ -554,7 +570,7 @@ static void pass_blame(git_blame *blame, git_blame__origin *origin, uint32_t opt
origin_decref(sg_origin[i]);
if (sg_origin != sg_buf)
git__free(sg_origin);
return;
return error;
}

/*
Expand Down Expand Up @@ -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;
Expand All @@ -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) {
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/blame_git.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,6 @@ int git_blame__get_origin(
git_commit *commit,
const char *path);
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
3 changes: 2 additions & 1 deletion src/checkout.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "git2/submodule.h"
#include "git2/sys/index.h"
#include "git2/sys/filter.h"
#include "git2/merge.h"

#include "refs.h"
#include "repository.h"
Expand All @@ -27,7 +28,7 @@
#include "diff.h"
#include "pathspec.h"
#include "buf_text.h"
#include "merge_file.h"
#include "diff_xdiff.h"
#include "path.h"
#include "attr.h"
#include "pool.h"
Expand Down
9 changes: 9 additions & 0 deletions src/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,15 @@ GIT_INLINE(void) git__init_structure(void *structure, size_t len, unsigned int v
#define GITERR_CHECK_ALLOC_ADD(out, one, two) \
if (GIT_ADD_SIZET_OVERFLOW(out, one, two)) { return -1; }

#define GITERR_CHECK_ALLOC_ADD3(out, one, two, three) \
if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \
GIT_ADD_SIZET_OVERFLOW(out, *(out), three)) { return -1; }

#define GITERR_CHECK_ALLOC_ADD4(out, one, two, three, four) \
if (GIT_ADD_SIZET_OVERFLOW(out, one, two) || \
GIT_ADD_SIZET_OVERFLOW(out, *(out), three) || \
GIT_ADD_SIZET_OVERFLOW(out, *(out), four)) { return -1; }

/** Check for multiplicative overflow, failing if it would occur. */
#define GITERR_CHECK_ALLOC_MULTIPLY(out, nelem, elsize) \
if (GIT_MULTIPLY_SIZET_OVERFLOW(out, nelem, elsize)) { return -1; }
Expand Down
4 changes: 4 additions & 0 deletions src/diff_patch.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ static void diff_patch_update_binary(git_patch *patch)
(patch->nfile.file->flags & GIT_DIFF_FLAG_BINARY) != 0)
patch->delta->flags |= GIT_DIFF_FLAG_BINARY;

else if (patch->ofile.file->size > GIT_XDIFF_MAX_SIZE ||
patch->nfile.file->size > GIT_XDIFF_MAX_SIZE)
patch->delta->flags |= GIT_DIFF_FLAG_BINARY;

else if ((patch->ofile.file->flags & DIFF_FLAGS_NOT_BINARY) != 0 &&
(patch->nfile.file->flags & DIFF_FLAGS_NOT_BINARY) != 0)
patch->delta->flags |= GIT_DIFF_FLAG_NOT_BINARY;
Expand Down
7 changes: 7 additions & 0 deletions src/diff_xdiff.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "git2/errors.h"
#include "common.h"
#include "diff.h"
#include "diff_driver.h"
Expand Down Expand Up @@ -208,6 +209,12 @@ static int git_xdiff(git_diff_output *output, git_patch *patch)
git_patch__old_data(&info.xd_old_data.ptr, &info.xd_old_data.size, patch);
git_patch__new_data(&info.xd_new_data.ptr, &info.xd_new_data.size, patch);

if (info.xd_old_data.size > GIT_XDIFF_MAX_SIZE ||
info.xd_new_data.size > GIT_XDIFF_MAX_SIZE) {
giterr_set(GITERR_INVALID, "files too large for diff");
return -1;
}

xdl_diff(&info.xd_old_data, &info.xd_new_data,
&xo->params, &xo->config, &xo->callback);

Expand Down
5 changes: 5 additions & 0 deletions src/diff_xdiff.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
#include "diff_patch.h"
#include "xdiff/xdiff.h"

/* xdiff cannot cope with large files. these files should not be passed to
* xdiff. callers should treat these large files as binary.
*/
#define GIT_XDIFF_MAX_SIZE (1024LL * 1024 * 1023)

/* A git_xdiff_output is a git_diff_output with extra fields necessary
* to use libxdiff. Calling git_xdiff_init() will set the diff_cb field
* of the output to use xdiff to generate the diffs.
Expand Down
56 changes: 0 additions & 56 deletions src/merge.c
Loading