Skip to content

Commit 0730dd4

Browse files
peffgitster
authored andcommitted
difftool: avoid strcpy
In order to checkout files, difftool reads "diff --raw" output and feeds the names to checkout_entry(). That function requires us to have a "struct cache_entry". And because that struct uses a FLEX_ARRAY for the name field, we have to actually copy in our new name. The current code allocates a single re-usable cache_entry that can hold a name up to PATH_MAX, and then copies filenames into it using strcpy(). But there's no guarantee that incoming names are smaller than PATH_MAX. They've come from "diff --raw" output which might be diffing between two trees (and hence we'd be subject to the PATH_MAX of some other system, or even none at all if they were created directly via "update-index"). We can fix this by using make_cache_entry() to create a correctly-sized cache_entry for each name. This incurs an extra allocation per file, but this is negligible compared to actually writing out the file contents. To make this simpler, we can push this procedure into a new helper function. Note that we can also get rid of the "len" variables for src_path and dst_path (and in fact we must, as the compiler complains that they are unused). Signed-off-by: Jeff King <[email protected]> Acked-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 18ec800 commit 0730dd4

File tree

1 file changed

+15
-16
lines changed

1 file changed

+15
-16
lines changed

builtin/difftool.c

Lines changed: 15 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,19 @@ static char *get_symlink(const struct object_id *oid, const char *path)
297297
return data;
298298
}
299299

300+
static int checkout_path(unsigned mode, struct object_id *oid,
301+
const char *path, const struct checkout *state)
302+
{
303+
struct cache_entry *ce;
304+
int ret;
305+
306+
ce = make_cache_entry(mode, oid->hash, path, 0, 0);
307+
ret = checkout_entry(ce, state, NULL);
308+
309+
free(ce);
310+
return ret;
311+
}
312+
300313
static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
301314
int argc, const char **argv)
302315
{
@@ -306,7 +319,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
306319
struct strbuf ldir = STRBUF_INIT, rdir = STRBUF_INIT;
307320
struct strbuf wtdir = STRBUF_INIT;
308321
size_t ldir_len, rdir_len, wtdir_len;
309-
struct cache_entry *ce = xcalloc(1, sizeof(ce) + PATH_MAX + 1);
310322
const char *workdir, *tmp;
311323
int ret = 0, i;
312324
FILE *fp;
@@ -377,7 +389,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
377389
struct object_id loid, roid;
378390
char status;
379391
const char *src_path, *dst_path;
380-
size_t src_path_len, dst_path_len;
381392

382393
if (starts_with(info.buf, "::"))
383394
die(N_("combined diff formats('-c' and '--cc') are "
@@ -390,17 +401,14 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
390401
if (strbuf_getline_nul(&lpath, fp))
391402
break;
392403
src_path = lpath.buf;
393-
src_path_len = lpath.len;
394404

395405
i++;
396406
if (status != 'C' && status != 'R') {
397407
dst_path = src_path;
398-
dst_path_len = src_path_len;
399408
} else {
400409
if (strbuf_getline_nul(&rpath, fp))
401410
break;
402411
dst_path = rpath.buf;
403-
dst_path_len = rpath.len;
404412
}
405413

406414
if (S_ISGITLINK(lmode) || S_ISGITLINK(rmode)) {
@@ -430,11 +438,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
430438
}
431439

432440
if (lmode && status != 'C') {
433-
ce->ce_mode = lmode;
434-
oidcpy(&ce->oid, &loid);
435-
strcpy(ce->name, src_path);
436-
ce->ce_namelen = src_path_len;
437-
if (checkout_entry(ce, &lstate, NULL))
441+
if (checkout_path(lmode, &loid, src_path, &lstate))
438442
return error("could not write '%s'", src_path);
439443
}
440444

@@ -451,11 +455,7 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
451455
hashmap_add(&working_tree_dups, entry);
452456

453457
if (!use_wt_file(workdir, dst_path, &roid)) {
454-
ce->ce_mode = rmode;
455-
oidcpy(&ce->oid, &roid);
456-
strcpy(ce->name, dst_path);
457-
ce->ce_namelen = dst_path_len;
458-
if (checkout_entry(ce, &rstate, NULL))
458+
if (checkout_path(rmode, &roid, dst_path, &rstate))
459459
return error("could not write '%s'",
460460
dst_path);
461461
} else if (!is_null_oid(&roid)) {
@@ -625,7 +625,6 @@ static int run_dir_diff(const char *extcmd, int symlinks, const char *prefix,
625625
exit_cleanup(tmpdir, rc);
626626

627627
finish:
628-
free(ce);
629628
strbuf_release(&ldir);
630629
strbuf_release(&rdir);
631630
strbuf_release(&wtdir);

0 commit comments

Comments
 (0)