Skip to content

Commit e4da43b

Browse files
peffgitster
authored andcommitted
prefix_filename: return newly allocated string
The prefix_filename() function returns a pointer to static storage, which makes it easy to use dangerously. We already fixed one buggy caller in hash-object recently, and the calls in apply.c are suspicious (I didn't dig in enough to confirm that there is a bug, but we call the function once in apply_all_patches() and then again indirectly from parse_chunk()). Let's make it harder to get wrong by allocating the return value. For simplicity, we'll do this even when the prefix is empty (and we could just return the original file pointer). That will cause us to allocate sometimes when we wouldn't otherwise need to, but this function isn't called in performance critical code-paths (and it already _might_ allocate on any given call, so a caller that cares about performance is questionable anyway). The downside is that the callers need to remember to free() the result to avoid leaking. Most of them already used xstrdup() on the result, so we know they are OK. The remainder have been converted to use free() as appropriate. I considered retaining a prefix_filename_unsafe() for cases where we know the static lifetime is OK (and handling the cleanup is awkward). This is only a handful of cases, though, and it's not worth the mental energy in worrying about whether the "unsafe" variant is OK to use in any situation. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 116fb64 commit e4da43b

File tree

15 files changed

+51
-39
lines changed

15 files changed

+51
-39
lines changed

abspath.c

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -246,26 +246,24 @@ char *absolute_pathdup(const char *path)
246246
return strbuf_detach(&sb, NULL);
247247
}
248248

249-
const char *prefix_filename(const char *pfx, const char *arg)
249+
char *prefix_filename(const char *pfx, const char *arg)
250250
{
251-
static struct strbuf path = STRBUF_INIT;
251+
struct strbuf path = STRBUF_INIT;
252252
size_t pfx_len = pfx ? strlen(pfx) : 0;
253253

254254
#ifndef GIT_WINDOWS_NATIVE
255255
if (!pfx_len || is_absolute_path(arg))
256-
return arg;
257-
strbuf_reset(&path);
256+
return xstrdup(arg);
258257
strbuf_add(&path, pfx, pfx_len);
259258
strbuf_addstr(&path, arg);
260259
#else
261260
/* don't add prefix to absolute paths, but still replace '\' by '/' */
262-
strbuf_reset(&path);
263261
if (is_absolute_path(arg))
264262
pfx_len = 0;
265263
else if (pfx_len)
266264
strbuf_add(&path, pfx, pfx_len);
267265
strbuf_addstr(&path, arg);
268266
convert_slashes(path.buf + pfx_len);
269267
#endif
270-
return path.buf;
268+
return strbuf_detach(&path, NULL);
271269
}

apply.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2046,7 +2046,7 @@ static void prefix_one(struct apply_state *state, char **name)
20462046
char *old_name = *name;
20472047
if (!old_name)
20482048
return;
2049-
*name = xstrdup(prefix_filename(state->prefix, *name));
2049+
*name = prefix_filename(state->prefix, *name);
20502050
free(old_name);
20512051
}
20522052

@@ -4805,6 +4805,7 @@ int apply_all_patches(struct apply_state *state,
48054805

48064806
for (i = 0; i < argc; i++) {
48074807
const char *arg = argv[i];
4808+
char *to_free = NULL;
48084809
int fd;
48094810

48104811
if (!strcmp(arg, "-")) {
@@ -4814,19 +4815,21 @@ int apply_all_patches(struct apply_state *state,
48144815
errs |= res;
48154816
read_stdin = 0;
48164817
continue;
4817-
} else if (0 < state->prefix_length)
4818-
arg = prefix_filename(state->prefix, arg);
4818+
} else
4819+
arg = to_free = prefix_filename(state->prefix, arg);
48194820

48204821
fd = open(arg, O_RDONLY);
48214822
if (fd < 0) {
48224823
error(_("can't open patch '%s': %s"), arg, strerror(errno));
48234824
res = -128;
4825+
free(to_free);
48244826
goto end;
48254827
}
48264828
read_stdin = 0;
48274829
set_default_whitespace_mode(state);
48284830
res = apply_patch(state, fd, arg, options);
48294831
close(fd);
4832+
free(to_free);
48304833
if (res < 0)
48314834
goto end;
48324835
errs |= res;

builtin/config.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -527,8 +527,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
527527
else if (given_config_source.file) {
528528
if (!is_absolute_path(given_config_source.file) && prefix)
529529
given_config_source.file =
530-
xstrdup(prefix_filename(prefix,
531-
given_config_source.file));
530+
prefix_filename(prefix, given_config_source.file);
532531
}
533532

534533
if (respect_includes == -1)

builtin/hash-object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
145145
char *to_free = NULL;
146146

147147
if (prefix)
148-
arg = to_free = xstrdup(prefix_filename(prefix, arg));
148+
arg = to_free = prefix_filename(prefix, arg);
149149
hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
150150
flags, literally);
151151
free(to_free);

builtin/log.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
10841084
if (!output_directory)
10851085
return prefix;
10861086

1087-
return xstrdup(prefix_filename(prefix, output_directory));
1087+
return prefix_filename(prefix, output_directory);
10881088
}
10891089

10901090
static const char * const builtin_format_patch_usage[] = {

builtin/mailinfo.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,6 @@
1111
static const char mailinfo_usage[] =
1212
"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info";
1313

14-
static char *prefix_copy(const char *prefix, const char *filename)
15-
{
16-
if (!prefix || is_absolute_path(filename))
17-
return xstrdup(filename);
18-
return xstrdup(prefix_filename(prefix, filename));
19-
}
20-
2114
int cmd_mailinfo(int argc, const char **argv, const char *prefix)
2215
{
2316
const char *def_charset;
@@ -60,8 +53,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
6053
mi.input = stdin;
6154
mi.output = stdout;
6255

63-
msgfile = prefix_copy(prefix, argv[1]);
64-
patchfile = prefix_copy(prefix, argv[2]);
56+
msgfile = prefix_filename(prefix, argv[1]);
57+
patchfile = prefix_filename(prefix, argv[2]);
6558

6659
status = !!mailinfo(&mi, msgfile, patchfile);
6760
clear_mailinfo(&mi);

builtin/merge-file.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,11 +65,18 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
6565
}
6666

6767
for (i = 0; i < 3; i++) {
68-
const char *fname = prefix_filename(prefix, argv[i]);
68+
char *fname;
69+
int ret;
70+
6971
if (!names[i])
7072
names[i] = argv[i];
71-
if (read_mmfile(mmfs + i, fname))
73+
74+
fname = prefix_filename(prefix, argv[i]);
75+
ret = read_mmfile(mmfs + i, fname);
76+
free(fname);
77+
if (ret)
7278
return -1;
79+
7380
if (mmfs[i].size > MAX_XDIFF_SIZE ||
7481
buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
7582
return error("Cannot merge binary files: %s",
@@ -86,7 +93,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
8693

8794
if (ret >= 0) {
8895
const char *filename = argv[0];
89-
const char *fpath = prefix_filename(prefix, argv[0]);
96+
char *fpath = prefix_filename(prefix, argv[0]);
9097
FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
9198

9299
if (!f)
@@ -98,6 +105,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
98105
else if (fclose(f))
99106
ret = error_errno("Could not close %s", filename);
100107
free(result.ptr);
108+
free(fpath);
101109
}
102110

103111
if (ret > 127)

builtin/rev-parse.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,9 @@ static int show_file(const char *arg, int output_prefix)
228228
if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
229229
if (output_prefix) {
230230
const char *prefix = startup_info->prefix;
231-
show(prefix_filename(prefix, arg));
231+
char *fname = prefix_filename(prefix, arg);
232+
show(fname);
233+
free(fname);
232234
} else
233235
show(arg);
234236
return 1;

builtin/worktree.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -318,7 +318,8 @@ static int add(int ac, const char **av, const char *prefix)
318318
{
319319
struct add_opts opts;
320320
const char *new_branch_force = NULL;
321-
const char *path, *branch;
321+
char *path;
322+
const char *branch;
322323
struct option options[] = {
323324
OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
324325
OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),

cache.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -537,10 +537,10 @@ extern char *prefix_path_gently(const char *prefix, int len, int *remaining, con
537537
* not have to interact with index entry; i.e. name of a random file
538538
* on the filesystem.
539539
*
540-
* The return value may point to static storage which will be overwritten by
541-
* further calls.
540+
* The return value is always a newly allocated string (even if the
541+
* prefix was empty).
542542
*/
543-
extern const char *prefix_filename(const char *prefix, const char *path);
543+
extern char *prefix_filename(const char *prefix, const char *path);
544544

545545
extern int check_filename(const char *prefix, const char *name);
546546
extern void verify_filename(const char *prefix,

0 commit comments

Comments
 (0)