Merge branch 'js/difftool-builtin'

Code cleanup.

* js/difftool-builtin:
  difftool: fix use-after-free
  difftool: avoid strcpy
This commit is contained in:
Junio C Hamano 2017-04-16 23:29:34 -07:00
commit 7b612c966e
2 changed files with 39 additions and 18 deletions

View File

@ -297,6 +297,19 @@ static char *get_symlink(const struct object_id *oid, const char *path)
return data; return data;
} }
static int checkout_path(unsigned mode, struct object_id *oid,
const char *path, const struct checkout *state)
{
struct cache_entry *ce;
int ret;
ce = make_cache_entry(mode, oid->hash, path, 0, 0);
ret = checkout_entry(ce, state, NULL);
free(ce);
return ret;
}
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix, static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
int argc, const char **argv) int argc, const char **argv)
{ {
@ -305,8 +318,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT; struct strbuf rpath = STRBUF_INIT, buf = STRBUF_INIT;
struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT; struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
struct strbuf wtdir = STRBUF_INIT; struct strbuf wtdir = STRBUF_INIT;
char *lbase_dir, *rbase_dir;
size_t ldir_len, rdir_len, wtdir_len; size_t ldir_len, rdir_len, wtdir_len;
struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1);
const char *workdir, *tmp; const char *workdir, *tmp;
int ret = 0, i; int ret = 0, i;
FILE *fp; FILE *fp;
@ -339,11 +352,11 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
memset(&wtindex, 0, sizeof(wtindex)); memset(&wtindex, 0, sizeof(wtindex));
memset(&lstate, 0, sizeof(lstate)); memset(&lstate, 0, sizeof(lstate));
lstate.base_dir = ldir.buf; lstate.base_dir = lbase_dir = xstrdup(ldir.buf);
lstate.base_dir_len = ldir.len; lstate.base_dir_len = ldir.len;
lstate.force = 1; lstate.force = 1;
memset(&rstate, 0, sizeof(rstate)); memset(&rstate, 0, sizeof(rstate));
rstate.base_dir = rdir.buf; rstate.base_dir = rbase_dir = xstrdup(rdir.buf);
rstate.base_dir_len = rdir.len; rstate.base_dir_len = rdir.len;
rstate.force = 1; rstate.force = 1;
@ -377,7 +390,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
struct object_id loid, roid; struct object_id loid, roid;
char status; char status;
const char *src_path, *dst_path; const char *src_path, *dst_path;
size_t src_path_len, dst_path_len;
if (starts_with(info.buf, "::")) if (starts_with(info.buf, "::"))
die(N_("combined diff formats('-c' and '--cc') are " die(N_("combined diff formats('-c' and '--cc') are "
@ -390,17 +402,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
if (strbuf_getline_nul(&lpath, fp)) if (strbuf_getline_nul(&lpath, fp))
break; break;
src_path = lpath.buf; src_path = lpath.buf;
src_path_len = lpath.len;
i++; i++;
if (status != 'C' && status != 'R') { if (status != 'C' && status != 'R') {
dst_path = src_path; dst_path = src_path;
dst_path_len = src_path_len;
} else { } else {
if (strbuf_getline_nul(&rpath, fp)) if (strbuf_getline_nul(&rpath, fp))
break; break;
dst_path = rpath.buf; dst_path = rpath.buf;
dst_path_len = rpath.len;
} }
if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) { if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) {
@ -430,11 +439,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
} }
if (lmode && status != 'C') { if (lmode && status != 'C') {
ce->ce_mode = lmode; if (checkout_path(lmode, &loid, src_path, &lstate))
oidcpy(&ce->oid, &loid);
strcpy(ce->name, src_path);
ce->ce_namelen = src_path_len;
if (checkout_entry(ce, &lstate, NULL))
return error("could not write '%s'", src_path); return error("could not write '%s'", src_path);
} }
@ -451,11 +456,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
hashmap_add(&working_tree_dups, entry); hashmap_add(&working_tree_dups, entry);
if (!use_wt_file(workdir, dst_path, &roid)) { if (!use_wt_file(workdir, dst_path, &roid)) {
ce->ce_mode = rmode; if (checkout_path(rmode, &roid, dst_path, &rstate))
oidcpy(&ce->oid, &roid);
strcpy(ce->name, dst_path);
ce->ce_namelen = dst_path_len;
if (checkout_entry(ce, &rstate, NULL))
return error("could not write '%s'", return error("could not write '%s'",
dst_path); dst_path);
} else if (!is_null_oid(&roid)) { } else if (!is_null_oid(&roid)) {
@ -625,7 +626,8 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
exit_cleanup(tmpdir, rc); exit_cleanup(tmpdir, rc);
finish: finish:
free(ce); free(lbase_dir);
free(rbase_dir);
strbuf_release(&ldir); strbuf_release(&ldir);
strbuf_release(&rdir); strbuf_release(&rdir);
strbuf_release(&wtdir); strbuf_release(&wtdir);

View File

@ -393,6 +393,25 @@ test_expect_success 'setup change in subdirectory' '
git commit -m "modified both" git commit -m "modified both"
' '
test_expect_success 'difftool -d with growing paths' '
a=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa &&
git init growing &&
(
cd growing &&
echo "test -f \"\$2/b\"" | write_script .git/test-for-b.sh &&
one=$(printf 1 | git hash-object -w --stdin) &&
two=$(printf 2 | git hash-object -w --stdin) &&
git update-index --add \
--cacheinfo 100644,$one,$a --cacheinfo 100644,$two,b &&
tree1=$(git write-tree) &&
git update-index --add \
--cacheinfo 100644,$two,$a --cacheinfo 100644,$one,b &&
tree2=$(git write-tree) &&
git checkout -- $a &&
git difftool -d --extcmd .git/test-for-b.sh $tree1 $tree2
)
'
run_dir_diff_test () { run_dir_diff_test () {
test_expect_success "$1 --no-symlinks" " test_expect_success "$1 --no-symlinks" "
symlinks=--no-symlinks && symlinks=--no-symlinks &&