Commit 71d27358 by Russell Belfer

Fix bug with merging diffs with null options

A diff that is created with a NULL options parameter could result
in a NULL prefix string, but diff merge was unconditionally
strdup'ing it.  I added a test to replicate the issue and then a
new method that does the right thing with NULL values.
parent 5a8204f8
......@@ -814,9 +814,9 @@ int git_diff_merge(
/* prefix strings also come from old pool, so recreate those.*/
onto->opts.old_prefix =
git_pool_strdup(&onto->pool, onto->opts.old_prefix);
git_pool_strdup_safe(&onto->pool, onto->opts.old_prefix);
onto->opts.new_prefix =
git_pool_strdup(&onto->pool, onto->opts.new_prefix);
git_pool_strdup_safe(&onto->pool, onto->opts.new_prefix);
}
git_vector_foreach(&onto_new, i, delta)
......
......@@ -206,6 +206,11 @@ char *git_pool_strdup(git_pool *pool, const char *str)
return git_pool_strndup(pool, str, strlen(str));
}
char *git_pool_strdup_safe(git_pool *pool, const char *str)
{
return str ? git_pool_strdup(pool, str) : NULL;
}
char *git_pool_strcat(git_pool *pool, const char *a, const char *b)
{
void *ptr;
......
......@@ -90,6 +90,13 @@ extern char *git_pool_strndup(git_pool *pool, const char *str, size_t n);
extern char *git_pool_strdup(git_pool *pool, const char *str);
/**
* Allocate space and duplicate a string into it, NULL is no error.
*
* This is allowed only for pools with item_size == sizeof(char)
*/
extern char *git_pool_strdup_safe(git_pool *pool, const char *str);
/**
* Allocate space for the concatenation of two strings.
*
* This is allowed only for pools with item_size == sizeof(char)
......
......@@ -208,3 +208,51 @@ void test_diff_tree__bare(void)
git_tree_free(a);
git_tree_free(b);
}
void test_diff_tree__merge(void)
{
/* grabbed a couple of commit oids from the history of the attr repo */
const char *a_commit = "605812a";
const char *b_commit = "370fe9ec22";
const char *c_commit = "f5b0af1fb4f5c";
git_tree *a, *b, *c;
git_diff_list *diff1 = NULL, *diff2 = NULL;
diff_expects exp;
g_repo = cl_git_sandbox_init("attr");
cl_assert((a = resolve_commit_oid_to_tree(g_repo, a_commit)) != NULL);
cl_assert((b = resolve_commit_oid_to_tree(g_repo, b_commit)) != NULL);
cl_assert((c = resolve_commit_oid_to_tree(g_repo, c_commit)) != NULL);
cl_git_pass(git_diff_tree_to_tree(g_repo, NULL, a, b, &diff1));
cl_git_pass(git_diff_tree_to_tree(g_repo, NULL, c, b, &diff2));
git_tree_free(a);
git_tree_free(b);
git_tree_free(c);
cl_git_pass(git_diff_merge(diff1, diff2));
git_diff_list_free(diff2);
memset(&exp, 0, sizeof(exp));
cl_git_pass(git_diff_foreach(
diff1, &exp, diff_file_fn, diff_hunk_fn, diff_line_fn));
cl_assert(exp.files == 6);
cl_assert(exp.file_adds == 2);
cl_assert(exp.file_dels == 1);
cl_assert(exp.file_mods == 3);
cl_assert(exp.hunks == 6);
cl_assert(exp.lines == 59);
cl_assert(exp.line_ctxt == 1);
cl_assert(exp.line_adds == 36);
cl_assert(exp.line_dels == 22);
git_diff_list_free(diff1);
}
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