diff options
author | Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com> | 2020-03-10 13:11:22 (GMT) |
---|---|---|
committer | Junio C Hamano <gitster@pobox.com> | 2020-03-10 18:41:40 (GMT) |
commit | 3d7747e318532a36a263c61cdf92f2decb6424ff (patch) | |
tree | 3d00f009afde0dea8008eb7a40b379c9225023e5 /builtin | |
parent | 0915a5b4cdf00a8c6c755b77b854725a183993b4 (diff) | |
download | git-3d7747e318532a36a263c61cdf92f2decb6424ff.zip git-3d7747e318532a36a263c61cdf92f2decb6424ff.tar.gz git-3d7747e318532a36a263c61cdf92f2decb6424ff.tar.bz2 |
real_path: remove unsafe API
Returning a shared buffer invites very subtle bugs due to reentrancy or
multi-threading, as demonstrated by the previous patch.
There was an unfinished effort to abolish this [1].
Let's finally rid of `real_path()`, using `strbuf_realpath()` instead.
This patch uses a local `strbuf` for most places where `real_path()` was
previously called.
However, two places return the value of `real_path()` to the caller. For
them, a `static` local `strbuf` was added, effectively pushing the
problem one level higher:
read_gitfile_gently()
get_superproject_working_tree()
[1] https://lore.kernel.org/git/1480964316-99305-1-git-send-email-bmwill@google.com/
Signed-off-by: Alexandr Miloslavskiy <alexandr.miloslavskiy@syntevo.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Diffstat (limited to 'builtin')
-rw-r--r-- | builtin/clone.c | 6 | ||||
-rw-r--r-- | builtin/commit-graph.c | 5 | ||||
-rw-r--r-- | builtin/rev-parse.c | 5 | ||||
-rw-r--r-- | builtin/worktree.c | 9 |
4 files changed, 19 insertions, 6 deletions
diff --git a/builtin/clone.c b/builtin/clone.c index 1ad26f4..488bdb0 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -420,6 +420,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, struct dir_iterator *iter; int iter_status; unsigned int flags; + struct strbuf realpath = STRBUF_INIT; mkdir_if_missing(dest->buf, 0777); @@ -454,7 +455,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, if (unlink(dest->buf) && errno != ENOENT) die_errno(_("failed to unlink '%s'"), dest->buf); if (!option_no_hardlinks) { - if (!link(real_path(src->buf), dest->buf)) + strbuf_realpath(&realpath, src->buf, 1); + if (!link(realpath.buf, dest->buf)) continue; if (option_local > 0) die_errno(_("failed to create link '%s'"), dest->buf); @@ -468,6 +470,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest, strbuf_setlen(src, src_len); die(_("failed to iterate over '%s'"), src->buf); } + + strbuf_release(&realpath); } static void clone_local(const char *src_repo, const char *dest_repo) diff --git a/builtin/commit-graph.c b/builtin/commit-graph.c index 4a70b33..d1ab662 100644 --- a/builtin/commit-graph.c +++ b/builtin/commit-graph.c @@ -39,14 +39,17 @@ static struct object_directory *find_odb(struct repository *r, { struct object_directory *odb; char *obj_dir_real = real_pathdup(obj_dir, 1); + struct strbuf odb_path_real = STRBUF_INIT; prepare_alt_odb(r); for (odb = r->objects->odb; odb; odb = odb->next) { - if (!strcmp(obj_dir_real, real_path(odb->path))) + strbuf_realpath(&odb_path_real, odb->path, 1); + if (!strcmp(obj_dir_real, odb_path_real.buf)) break; } free(obj_dir_real); + strbuf_release(&odb_path_real); if (!odb) die(_("could not find object directory matching %s"), obj_dir); diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 7a00da8..06ca717 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -857,7 +857,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) if (!gitdir && !prefix) gitdir = ".git"; if (gitdir) { - puts(real_path(gitdir)); + struct strbuf realpath = STRBUF_INIT; + strbuf_realpath(&realpath, gitdir, 1); + puts(realpath.buf); + strbuf_release(&realpath); continue; } } diff --git a/builtin/worktree.c b/builtin/worktree.c index 24f2280..d99db35 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -258,7 +258,7 @@ static int add_worktree(const char *path, const char *refname, const struct add_opts *opts) { struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT; - struct strbuf sb = STRBUF_INIT; + struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT; const char *name; struct child_process cp = CHILD_PROCESS_INIT; struct argv_array child_env = ARGV_ARRAY_INIT; @@ -330,9 +330,11 @@ static int add_worktree(const char *path, const char *refname, strbuf_reset(&sb); strbuf_addf(&sb, "%s/gitdir", sb_repo.buf); - write_file(sb.buf, "%s", real_path(sb_git.buf)); + strbuf_realpath(&realpath, sb_git.buf, 1); + write_file(sb.buf, "%s", realpath.buf); + strbuf_realpath(&realpath, get_git_common_dir(), 1); write_file(sb_git.buf, "gitdir: %s/worktrees/%s", - real_path(get_git_common_dir()), name); + realpath.buf, name); /* * This is to keep resolve_ref() happy. We need a valid HEAD * or is_git_directory() will reject the directory. Any value which @@ -418,6 +420,7 @@ done: strbuf_release(&sb_repo); strbuf_release(&sb_git); strbuf_release(&sb_name); + strbuf_release(&realpath); return ret; } |