Skip to content

Commit 3d7747e

Browse files
SyntevoAlexgitster
authored andcommittedMar 10, 2020
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/[email protected]/ Signed-off-by: Alexandr Miloslavskiy <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0915a5b commit 3d7747e

13 files changed

+59
-24
lines changed
 

‎abspath.c

+1-7
Original file line numberDiff line numberDiff line change
@@ -206,12 +206,6 @@ char *strbuf_realpath(struct strbuf *resolved, const char *path,
206206
* Resolve `path` into an absolute, cleaned-up path. The return value
207207
* comes from a shared buffer.
208208
*/
209-
const char *real_path(const char *path)
210-
{
211-
static struct strbuf realpath = STRBUF_INIT;
212-
return strbuf_realpath(&realpath, path, 1);
213-
}
214-
215209
const char *real_path_if_valid(const char *path)
216210
{
217211
static struct strbuf realpath = STRBUF_INIT;
@@ -233,7 +227,7 @@ char *real_pathdup(const char *path, int die_on_error)
233227

234228
/*
235229
* Use this to get an absolute path from a relative one. If you want
236-
* to resolve links, you should use real_path.
230+
* to resolve links, you should use strbuf_realpath.
237231
*/
238232
const char *absolute_path(const char *path)
239233
{

‎builtin/clone.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,7 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
420420
struct dir_iterator *iter;
421421
int iter_status;
422422
unsigned int flags;
423+
struct strbuf realpath = STRBUF_INIT;
423424

424425
mkdir_if_missing(dest->buf, 0777);
425426

@@ -454,7 +455,8 @@ static void copy_or_link_directory(struct strbuf *src, struct strbuf *dest,
454455
if (unlink(dest->buf) && errno != ENOENT)
455456
die_errno(_("failed to unlink '%s'"), dest->buf);
456457
if (!option_no_hardlinks) {
457-
if (!link(real_path(src->buf), dest->buf))
458+
strbuf_realpath(&realpath, src->buf, 1);
459+
if (!link(realpath.buf, dest->buf))
458460
continue;
459461
if (option_local > 0)
460462
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,
468470
strbuf_setlen(src, src_len);
469471
die(_("failed to iterate over '%s'"), src->buf);
470472
}
473+
474+
strbuf_release(&realpath);
471475
}
472476

473477
static void clone_local(const char *src_repo, const char *dest_repo)

‎builtin/commit-graph.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,17 @@ static struct object_directory *find_odb(struct repository *r,
3939
{
4040
struct object_directory *odb;
4141
char *obj_dir_real = real_pathdup(obj_dir, 1);
42+
struct strbuf odb_path_real = STRBUF_INIT;
4243

4344
prepare_alt_odb(r);
4445
for (odb = r->objects->odb; odb; odb = odb->next) {
45-
if (!strcmp(obj_dir_real, real_path(odb->path)))
46+
strbuf_realpath(&odb_path_real, odb->path, 1);
47+
if (!strcmp(obj_dir_real, odb_path_real.buf))
4648
break;
4749
}
4850

4951
free(obj_dir_real);
52+
strbuf_release(&odb_path_real);
5053

5154
if (!odb)
5255
die(_("could not find object directory matching %s"), obj_dir);

‎builtin/rev-parse.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -857,7 +857,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)
857857
if (!gitdir && !prefix)
858858
gitdir = ".git";
859859
if (gitdir) {
860-
puts(real_path(gitdir));
860+
struct strbuf realpath = STRBUF_INIT;
861+
strbuf_realpath(&realpath, gitdir, 1);
862+
puts(realpath.buf);
863+
strbuf_release(&realpath);
861864
continue;
862865
}
863866
}

‎builtin/worktree.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,7 @@ static int add_worktree(const char *path, const char *refname,
258258
const struct add_opts *opts)
259259
{
260260
struct strbuf sb_git = STRBUF_INIT, sb_repo = STRBUF_INIT;
261-
struct strbuf sb = STRBUF_INIT;
261+
struct strbuf sb = STRBUF_INIT, realpath = STRBUF_INIT;
262262
const char *name;
263263
struct child_process cp = CHILD_PROCESS_INIT;
264264
struct argv_array child_env = ARGV_ARRAY_INIT;
@@ -330,9 +330,11 @@ static int add_worktree(const char *path, const char *refname,
330330

331331
strbuf_reset(&sb);
332332
strbuf_addf(&sb, "%s/gitdir", sb_repo.buf);
333-
write_file(sb.buf, "%s", real_path(sb_git.buf));
333+
strbuf_realpath(&realpath, sb_git.buf, 1);
334+
write_file(sb.buf, "%s", realpath.buf);
335+
strbuf_realpath(&realpath, get_git_common_dir(), 1);
334336
write_file(sb_git.buf, "gitdir: %s/worktrees/%s",
335-
real_path(get_git_common_dir()), name);
337+
realpath.buf, name);
336338
/*
337339
* This is to keep resolve_ref() happy. We need a valid HEAD
338340
* or is_git_directory() will reject the directory. Any value which
@@ -418,6 +420,7 @@ static int add_worktree(const char *path, const char *refname,
418420
strbuf_release(&sb_repo);
419421
strbuf_release(&sb_git);
420422
strbuf_release(&sb_name);
423+
strbuf_release(&realpath);
421424
return ret;
422425
}
423426

‎cache.h

-1
Original file line numberDiff line numberDiff line change
@@ -1314,7 +1314,6 @@ static inline int is_absolute_path(const char *path)
13141314
int is_directory(const char *);
13151315
char *strbuf_realpath(struct strbuf *resolved, const char *path,
13161316
int die_on_error);
1317-
const char *real_path(const char *path);
13181317
const char *real_path_if_valid(const char *path);
13191318
char *real_pathdup(const char *path, int die_on_error);
13201319
const char *absolute_path(const char *path);

‎editor.c

+9-2
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ static int launch_specified_editor(const char *editor, const char *path,
5454
return error("Terminal is dumb, but EDITOR unset");
5555

5656
if (strcmp(editor, ":")) {
57-
const char *args[] = { editor, real_path(path), NULL };
57+
struct strbuf realpath = STRBUF_INIT;
58+
const char *args[] = { editor, NULL, NULL };
5859
struct child_process p = CHILD_PROCESS_INIT;
5960
int ret, sig;
6061
int print_waiting_for_editor = advice_waiting_for_editor && isatty(2);
@@ -75,16 +76,22 @@ static int launch_specified_editor(const char *editor, const char *path,
7576
fflush(stderr);
7677
}
7778

79+
strbuf_realpath(&realpath, path, 1);
80+
args[1] = realpath.buf;
81+
7882
p.argv = args;
7983
p.env = env;
8084
p.use_shell = 1;
8185
p.trace2_child_class = "editor";
82-
if (start_command(&p) < 0)
86+
if (start_command(&p) < 0) {
87+
strbuf_release(&realpath);
8388
return error("unable to start editor '%s'", editor);
89+
}
8490

8591
sigchain_push(SIGINT, SIG_IGN);
8692
sigchain_push(SIGQUIT, SIG_IGN);
8793
ret = finish_command(&p);
94+
strbuf_release(&realpath);
8895
sig = ret - 128;
8996
sigchain_pop(SIGINT);
9097
sigchain_pop(SIGQUIT);

‎environment.c

+6-1
Original file line numberDiff line numberDiff line change
@@ -254,8 +254,11 @@ static int git_work_tree_initialized;
254254
*/
255255
void set_git_work_tree(const char *new_work_tree)
256256
{
257+
struct strbuf realpath = STRBUF_INIT;
258+
257259
if (git_work_tree_initialized) {
258-
new_work_tree = real_path(new_work_tree);
260+
strbuf_realpath(&realpath, new_work_tree, 1);
261+
new_work_tree = realpath.buf;
259262
if (strcmp(new_work_tree, the_repository->worktree))
260263
die("internal error: work tree has already been set\n"
261264
"Current worktree: %s\nNew worktree: %s",
@@ -264,6 +267,8 @@ void set_git_work_tree(const char *new_work_tree)
264267
}
265268
git_work_tree_initialized = 1;
266269
repo_set_worktree(the_repository, new_work_tree);
270+
271+
strbuf_release(&realpath);
267272
}
268273

269274
const char *get_git_work_tree(void)

‎path.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ static struct passwd *getpw_str(const char *username, size_t len)
723723
* then it is a newly allocated string. Returns NULL on getpw failure or
724724
* if path is NULL.
725725
*
726-
* If real_home is true, real_path($HOME) is used in the expansion.
726+
* If real_home is true, strbuf_realpath($HOME) is used in the expansion.
727727
*/
728728
char *expand_user_path(const char *path, int real_home)
729729
{

‎setup.c

+12-3
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ static int abspath_part_inside_repo(char *path)
3232
char *path0;
3333
int off;
3434
const char *work_tree = get_git_work_tree();
35+
struct strbuf realpath = STRBUF_INIT;
3536

3637
if (!work_tree)
3738
return -1;
@@ -60,20 +61,25 @@ static int abspath_part_inside_repo(char *path)
6061
path++;
6162
if (*path == '/') {
6263
*path = '\0';
63-
if (fspathcmp(real_path(path0), work_tree) == 0) {
64+
strbuf_realpath(&realpath, path0, 1);
65+
if (fspathcmp(realpath.buf, work_tree) == 0) {
6466
memmove(path0, path + 1, len - (path - path0));
67+
strbuf_release(&realpath);
6568
return 0;
6669
}
6770
*path = '/';
6871
}
6972
}
7073

7174
/* check whole path */
72-
if (fspathcmp(real_path(path0), work_tree) == 0) {
75+
strbuf_realpath(&realpath, path0, 1);
76+
if (fspathcmp(realpath.buf, work_tree) == 0) {
7377
*path0 = '\0';
78+
strbuf_release(&realpath);
7479
return 0;
7580
}
7681

82+
strbuf_release(&realpath);
7783
return -1;
7884
}
7985

@@ -619,6 +625,7 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
619625
struct stat st;
620626
int fd;
621627
ssize_t len;
628+
static struct strbuf realpath = STRBUF_INIT;
622629

623630
if (stat(path, &st)) {
624631
/* NEEDSWORK: discern between ENOENT vs other errors */
@@ -669,7 +676,9 @@ const char *read_gitfile_gently(const char *path, int *return_error_code)
669676
error_code = READ_GITFILE_ERR_NOT_A_REPO;
670677
goto cleanup_return;
671678
}
672-
path = real_path(dir);
679+
680+
strbuf_realpath(&realpath, dir, 1);
681+
path = realpath.buf;
673682

674683
cleanup_return:
675684
if (return_error_code)

‎submodule.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -2170,6 +2170,7 @@ void absorb_git_dir_into_superproject(const char *path,
21702170

21712171
const char *get_superproject_working_tree(void)
21722172
{
2173+
static struct strbuf realpath = STRBUF_INIT;
21732174
struct child_process cp = CHILD_PROCESS_INIT;
21742175
struct strbuf sb = STRBUF_INIT;
21752176
const char *one_up = real_path_if_valid("../");
@@ -2231,7 +2232,8 @@ const char *get_superproject_working_tree(void)
22312232
super_wt = xstrdup(cwd);
22322233
super_wt[cwd_len - super_sub_len] = '\0';
22332234

2234-
ret = real_path(super_wt);
2235+
strbuf_realpath(&realpath, super_wt, 1);
2236+
ret = realpath.buf;
22352237
free(super_wt);
22362238
}
22372239
strbuf_release(&sb);

‎t/helper/test-path-utils.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -290,11 +290,14 @@ int cmd__path_utils(int argc, const char **argv)
290290
}
291291

292292
if (argc >= 2 && !strcmp(argv[1], "real_path")) {
293+
struct strbuf realpath = STRBUF_INIT;
293294
while (argc > 2) {
294-
puts(real_path(argv[2]));
295+
strbuf_realpath(&realpath, argv[2], 1);
296+
puts(realpath.buf);
295297
argc--;
296298
argv++;
297299
}
300+
strbuf_release(&realpath);
298301
return 0;
299302
}
300303

‎worktree.c

+4-1
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,7 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
285285
unsigned flags)
286286
{
287287
struct strbuf wt_path = STRBUF_INIT;
288+
struct strbuf realpath = STRBUF_INIT;
288289
char *path = NULL;
289290
int err, ret = -1;
290291

@@ -336,14 +337,16 @@ int validate_worktree(const struct worktree *wt, struct strbuf *errmsg,
336337
goto done;
337338
}
338339

339-
ret = fspathcmp(path, real_path(git_common_path("worktrees/%s", wt->id)));
340+
strbuf_realpath(&realpath, git_common_path("worktrees/%s", wt->id), 1);
341+
ret = fspathcmp(path, realpath.buf);
340342

341343
if (ret)
342344
strbuf_addf_gently(errmsg, _("'%s' does not point back to '%s'"),
343345
wt->path, git_common_path("worktrees/%s", wt->id));
344346
done:
345347
free(path);
346348
strbuf_release(&wt_path);
349+
strbuf_release(&realpath);
347350
return ret;
348351
}
349352

0 commit comments

Comments
 (0)
Please sign in to comment.