git@vger.kernel.org mailing list mirror (one of many)
 help / Atom feed
* [PATCH 0/6] prefix_filename cleanups
@ 2017-03-21  1:18 Jeff King
  2017-03-21  1:20 ` [PATCH 1/6] hash-object: fix buffer reuse with --path in a subdirectory Jeff King
                   ` (6 more replies)
  0 siblings, 7 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:18 UTC (permalink / raw)
  To: git

I noticed a spot in builtin/bundle.c that would benefit from using
prefix_filename(). But when I tried to use it, I noticed its interface
was a little error-prone (because it returns a static buffer). And
indeed, a little digging found a bug in hash-object related to this.

So here's the fix for the hash-object bug, some cleanups to make such
bugs less likely, and then finally the bundle conversion. The bundle
thing does fix some minor bugs. It _could_ come before the cleanups if
we wanted to float the fixes to the top, but the function is much more
pleasant to call after the cleanups. :)

  [1/6]: hash-object: fix buffer reuse with --path in a subdirectory
  [2/6]: prefix_filename: move docstring to header file
  [3/6]: prefix_filename: drop length parameter
  [4/6]: prefix_filename: return newly allocated string
  [5/6]: prefix_filename: simplify windows #ifdef
  [6/6]: bundle: use prefix_filename with bundle path

 abspath.c              | 30 +++++++++++-------------------
 apply.c                | 11 ++++++-----
 builtin/bundle.c       |  8 +-------
 builtin/config.c       |  4 +---
 builtin/hash-object.c  | 10 +++++-----
 builtin/log.c          |  3 +--
 builtin/mailinfo.c     | 11 ++---------
 builtin/merge-file.c   | 18 +++++++++++-------
 builtin/rev-parse.c    |  6 +++---
 builtin/worktree.c     |  5 +++--
 cache.h                | 14 +++++++++++++-
 diff-no-index.c        |  7 +++----
 diff.c                 |  6 +++---
 parse-options.c        |  2 +-
 setup.c                | 11 ++++++++---
 t/t1007-hash-object.sh | 10 ++++++++++
 worktree.c             |  5 ++++-
 17 files changed, 86 insertions(+), 75 deletions(-)

-Peff

^ permalink raw reply	[flat|threaded] 11+ messages in thread

* [PATCH 1/6] hash-object: fix buffer reuse with --path in a subdirectory
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
@ 2017-03-21  1:20 ` Jeff King
  2017-03-21  1:21 ` [PATCH 2/6] prefix_filename: move docstring to header file Jeff King
                   ` (5 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:20 UTC (permalink / raw)
  To: git

The hash-object command uses prefix_filename() without
duplicating its return value. Since that function returns a
static buffer, the value is overwritten by subsequent calls.

This can cause incorrect results when we use --path along
with hashing a file by its relative path, both of which need
to call prefix_filename(). We overwrite the filename
computed for --path, effectively ignoring it.

We can fix this by calling xstrdup on the return value. Note
that we don't bother freeing the "vpath" instance, as it
remains valid until the program exit.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/hash-object.c  |  7 +++++--
 t/t1007-hash-object.sh | 10 ++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 9028e1fdc..56df77b0c 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -115,7 +115,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
 
 	prefix_length = prefix ? strlen(prefix) : 0;
 	if (vpath && prefix)
-		vpath = prefix_filename(prefix, prefix_length, vpath);
+		vpath = xstrdup(prefix_filename(prefix, prefix_length, vpath));
 
 	git_config(git_default_config, NULL);
 
@@ -144,11 +144,14 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
 
 	for (i = 0 ; i < argc; i++) {
 		const char *arg = argv[i];
+		char *to_free = NULL;
 
 		if (0 <= prefix_length)
-			arg = prefix_filename(prefix, prefix_length, arg);
+			arg = to_free =
+				xstrdup(prefix_filename(prefix, prefix_length, arg));
 		hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
 			    flags, literally);
+		free(to_free);
 	}
 
 	if (stdin_paths)
diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh
index c5245c5cb..532682f51 100755
--- a/t/t1007-hash-object.sh
+++ b/t/t1007-hash-object.sh
@@ -134,6 +134,16 @@ test_expect_success 'gitattributes also work in a subdirectory' '
 	)
 '
 
+test_expect_success '--path works in a subdirectory' '
+	(
+		cd subdir &&
+		path1_sha=$(git hash-object --path=../file1 ../file0) &&
+		path0_sha=$(git hash-object --path=../file0 ../file1) &&
+		test "$file0_sha" = "$path0_sha" &&
+		test "$file1_sha" = "$path1_sha"
+	)
+'
+
 test_expect_success 'check that --no-filters option works' '
 	nofilters_file1=$(git hash-object --no-filters file1) &&
 	test "$file0_sha" = "$nofilters_file1" &&
-- 
2.12.1.683.gcd02edfec


^ permalink raw reply	[flat|threaded] 11+ messages in thread

* [PATCH 2/6] prefix_filename: move docstring to header file
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
  2017-03-21  1:20 ` [PATCH 1/6] hash-object: fix buffer reuse with --path in a subdirectory Jeff King
@ 2017-03-21  1:21 ` Jeff King
  2017-03-21  1:22 ` [PATCH 3/6] prefix_filename: drop length parameter Jeff King
                   ` (4 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:21 UTC (permalink / raw)
  To: git

This is a public function, so we should make its
documentation available near the declaration.

While we're at it, we can give a few details about how it
works.

Signed-off-by: Jeff King <peff@peff.net>
---
 abspath.c |  5 -----
 cache.h   | 12 ++++++++++++
 2 files changed, 12 insertions(+), 5 deletions(-)

diff --git a/abspath.c b/abspath.c
index b02e068aa..fd30aff08 100644
--- a/abspath.c
+++ b/abspath.c
@@ -246,11 +246,6 @@ char *absolute_pathdup(const char *path)
 	return strbuf_detach(&sb, NULL);
 }
 
-/*
- * Unlike prefix_path, this should be used if the named file does
- * not have to interact with index entry; i.e. name of a random file
- * on the filesystem.
- */
 const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
 {
 	static struct strbuf path = STRBUF_INIT;
diff --git a/cache.h b/cache.h
index 9b2157f59..a01668fc4 100644
--- a/cache.h
+++ b/cache.h
@@ -529,7 +529,19 @@ extern const char *setup_git_directory_gently(int *);
 extern const char *setup_git_directory(void);
 extern char *prefix_path(const char *prefix, int len, const char *path);
 extern char *prefix_path_gently(const char *prefix, int len, int *remaining, const char *path);
+
+/*
+ * Concatenate "prefix" (if len is non-zero) and "path", with no
+ * connecting characters (so "prefix" should end with a "/").
+ * Unlike prefix_path, this should be used if the named file does
+ * not have to interact with index entry; i.e. name of a random file
+ * on the filesystem.
+ *
+ * The return value may point to static storage which will be overwritten by
+ * further calls.
+ */
 extern const char *prefix_filename(const char *prefix, int len, const char *path);
+
 extern int check_filename(const char *prefix, const char *name);
 extern void verify_filename(const char *prefix,
 			    const char *name,
-- 
2.12.1.683.gcd02edfec


^ permalink raw reply	[flat|threaded] 11+ messages in thread

* [PATCH 3/6] prefix_filename: drop length parameter
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
  2017-03-21  1:20 ` [PATCH 1/6] hash-object: fix buffer reuse with --path in a subdirectory Jeff King
  2017-03-21  1:21 ` [PATCH 2/6] prefix_filename: move docstring to header file Jeff King
@ 2017-03-21  1:22 ` Jeff King
  2017-03-21  1:28 ` [PATCH 4/6] prefix_filename: return newly allocated string Jeff King
                   ` (3 subsequent siblings)
  6 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:22 UTC (permalink / raw)
  To: git

This function takes the prefix as a ptr/len pair, but in
every caller the length is exactly strlen(ptr). Let's
simplify the interface and just take the string. This saves
callers specifying it (and in some cases handling a NULL
prefix).

In a handful of cases we had the length already without
calling strlen, so this is technically slower. But it's not
likely to matter (after all, if the prefix is non-empty
we'll allocate and copy it into a buffer anyway).

Signed-off-by: Jeff King <peff@peff.net>
---
 abspath.c             | 4 +++-
 apply.c               | 6 ++----
 builtin/config.c      | 1 -
 builtin/hash-object.c | 9 +++------
 builtin/log.c         | 3 +--
 builtin/mailinfo.c    | 2 +-
 builtin/merge-file.c  | 8 ++------
 builtin/rev-parse.c   | 4 +---
 builtin/worktree.c    | 2 +-
 cache.h               | 2 +-
 diff-no-index.c       | 7 +++----
 diff.c                | 4 ++--
 parse-options.c       | 2 +-
 setup.c               | 2 +-
 worktree.c            | 2 +-
 15 files changed, 23 insertions(+), 35 deletions(-)

diff --git a/abspath.c b/abspath.c
index fd30aff08..c6f480993 100644
--- a/abspath.c
+++ b/abspath.c
@@ -246,9 +246,11 @@ char *absolute_pathdup(const char *path)
 	return strbuf_detach(&sb, NULL);
 }
 
-const char *prefix_filename(const char *pfx, int pfx_len, const char *arg)
+const char *prefix_filename(const char *pfx, const char *arg)
 {
 	static struct strbuf path = STRBUF_INIT;
+	size_t pfx_len = pfx ? strlen(pfx) : 0;
+
 #ifndef GIT_WINDOWS_NATIVE
 	if (!pfx_len || is_absolute_path(arg))
 		return arg;
diff --git a/apply.c b/apply.c
index 0e2caeab9..b8bd5a4be 100644
--- a/apply.c
+++ b/apply.c
@@ -2046,7 +2046,7 @@ static void prefix_one(struct apply_state *state, char **name)
 	char *old_name = *name;
 	if (!old_name)
 		return;
-	*name = xstrdup(prefix_filename(state->prefix, state->prefix_length, *name));
+	*name = xstrdup(prefix_filename(state->prefix, *name));
 	free(old_name);
 }
 
@@ -4815,9 +4815,7 @@ int apply_all_patches(struct apply_state *state,
 			read_stdin = 0;
 			continue;
 		} else if (0 < state->prefix_length)
-			arg = prefix_filename(state->prefix,
-					      state->prefix_length,
-					      arg);
+			arg = prefix_filename(state->prefix, arg);
 
 		fd = open(arg, O_RDONLY);
 		if (fd < 0) {
diff --git a/builtin/config.c b/builtin/config.c
index 05843a0f9..74f6c34d1 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -528,7 +528,6 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
 				xstrdup(prefix_filename(prefix,
-							strlen(prefix),
 							given_config_source.file));
 	}
 
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 56df77b0c..2ea36909d 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -102,7 +102,6 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
 		OPT_END()
 	};
 	int i;
-	int prefix_length = -1;
 	const char *errstr = NULL;
 
 	argc = parse_options(argc, argv, NULL, hash_object_options,
@@ -113,9 +112,8 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
 	else
 		prefix = setup_git_directory_gently(&nongit);
 
-	prefix_length = prefix ? strlen(prefix) : 0;
 	if (vpath && prefix)
-		vpath = xstrdup(prefix_filename(prefix, prefix_length, vpath));
+		vpath = xstrdup(prefix_filename(prefix, vpath));
 
 	git_config(git_default_config, NULL);
 
@@ -146,9 +144,8 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
 		const char *arg = argv[i];
 		char *to_free = NULL;
 
-		if (0 <= prefix_length)
-			arg = to_free =
-				xstrdup(prefix_filename(prefix, prefix_length, arg));
+		if (prefix)
+			arg = to_free = xstrdup(prefix_filename(prefix, arg));
 		hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
 			    flags, literally);
 		free(to_free);
diff --git a/builtin/log.c b/builtin/log.c
index 281af8c1e..bfdc7a23d 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1084,8 +1084,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
 	if (!output_directory)
 		return prefix;
 
-	return xstrdup(prefix_filename(prefix, outdir_offset,
-				       output_directory));
+	return xstrdup(prefix_filename(prefix, output_directory));
 }
 
 static const char * const builtin_format_patch_usage[] = {
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index e3b62f2fc..681f07f54 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -15,7 +15,7 @@ static char *prefix_copy(const char *prefix, const char *filename)
 {
 	if (!prefix || is_absolute_path(filename))
 		return xstrdup(filename);
-	return xstrdup(prefix_filename(prefix, strlen(prefix), filename));
+	return xstrdup(prefix_filename(prefix, filename));
 }
 
 int cmd_mailinfo(int argc, const char **argv, const char *prefix)
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 13e22a2f0..63cd94358 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -28,7 +28,6 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 	xmparam_t xmp = {{0}};
 	int ret = 0, i = 0, to_stdout = 0;
 	int quiet = 0;
-	int prefixlen = 0;
 	struct option options[] = {
 		OPT_BOOL('p', "stdout", &to_stdout, N_("send results to standard output")),
 		OPT_SET_INT(0, "diff3", &xmp.style, N_("use a diff3 based merge"), XDL_MERGE_DIFF3),
@@ -65,11 +64,8 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 			return error_errno("failed to redirect stderr to /dev/null");
 	}
 
-	if (prefix)
-		prefixlen = strlen(prefix);
-
 	for (i = 0; i < 3; i++) {
-		const char *fname = prefix_filename(prefix, prefixlen, argv[i]);
+		const char *fname = prefix_filename(prefix, argv[i]);
 		if (!names[i])
 			names[i] = argv[i];
 		if (read_mmfile(mmfs + i, fname))
@@ -90,7 +86,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
 	if (ret >= 0) {
 		const char *filename = argv[0];
-		const char *fpath = prefix_filename(prefix, prefixlen, argv[0]);
+		const char *fpath = prefix_filename(prefix, argv[0]);
 		FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
 
 		if (!f)
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index 254964326..c8035331e 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -228,9 +228,7 @@ static int show_file(const char *arg, int output_prefix)
 	if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
 		if (output_prefix) {
 			const char *prefix = startup_info->prefix;
-			show(prefix_filename(prefix,
-					     prefix ? strlen(prefix) : 0,
-					     arg));
+			show(prefix_filename(prefix, arg));
 		} else
 			show(arg);
 		return 1;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index 831fe058a..e38325e44 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -338,7 +338,7 @@ static int add(int ac, const char **av, const char *prefix)
 	if (ac < 1 || ac > 2)
 		usage_with_options(worktree_usage, options);
 
-	path = prefix_filename(prefix, strlen(prefix), av[0]);
+	path = prefix_filename(prefix, av[0]);
 	branch = ac < 2 ? "HEAD" : av[1];
 
 	if (!strcmp(branch, "-"))
diff --git a/cache.h b/cache.h
index a01668fc4..0b53aef0e 100644
--- a/cache.h
+++ b/cache.h
@@ -540,7 +540,7 @@ extern char *prefix_path_gently(const char *prefix, int len, int *remaining, con
  * The return value may point to static storage which will be overwritten by
  * further calls.
  */
-extern const char *prefix_filename(const char *prefix, int len, const char *path);
+extern const char *prefix_filename(const char *prefix, const char *path);
 
 extern int check_filename(const char *prefix, const char *name);
 extern void verify_filename(const char *prefix,
diff --git a/diff-no-index.c b/diff-no-index.c
index df762fd0f..5f7317ced 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -236,7 +236,7 @@ static void fixup_paths(const char **path, struct strbuf *replacement)
 void diff_no_index(struct rev_info *revs,
 		   int argc, const char **argv)
 {
-	int i, prefixlen;
+	int i;
 	const char *paths[2];
 	struct strbuf replacement = STRBUF_INIT;
 	const char *prefix = revs->prefix;
@@ -257,7 +257,6 @@ void diff_no_index(struct rev_info *revs,
 		}
 	}
 
-	prefixlen = prefix ? strlen(prefix) : 0;
 	for (i = 0; i < 2; i++) {
 		const char *p = argv[argc - 2 + i];
 		if (!strcmp(p, "-"))
@@ -266,8 +265,8 @@ void diff_no_index(struct rev_info *revs,
 			 * path that is "-", spell it as "./-".
 			 */
 			p = file_from_standard_input;
-		else if (prefixlen)
-			p = xstrdup(prefix_filename(prefix, prefixlen, p));
+		else if (prefix)
+			p = xstrdup(prefix_filename(prefix, p));
 		paths[i] = p;
 	}
 
diff --git a/diff.c b/diff.c
index a628ac3a9..70870b4b6 100644
--- a/diff.c
+++ b/diff.c
@@ -4023,7 +4023,7 @@ int diff_opt_parse(struct diff_options *options,
 	else if (!strcmp(arg, "--pickaxe-regex"))
 		options->pickaxe_opts |= DIFF_PICKAXE_REGEX;
 	else if ((argcount = short_opt('O', av, &optarg))) {
-		const char *path = prefix_filename(prefix, strlen(prefix), optarg);
+		const char *path = prefix_filename(prefix, optarg);
 		options->orderfile = xstrdup(path);
 		return argcount;
 	}
@@ -4071,7 +4071,7 @@ int diff_opt_parse(struct diff_options *options,
 	else if (!strcmp(arg, "--no-function-context"))
 		DIFF_OPT_CLR(options, FUNCCONTEXT);
 	else if ((argcount = parse_long_opt("output", av, &optarg))) {
-		const char *path = prefix_filename(prefix, strlen(prefix), optarg);
+		const char *path = prefix_filename(prefix, optarg);
 		options->file = fopen(path, "w");
 		if (!options->file)
 			die_errno("Could not open '%s'", path);
diff --git a/parse-options.c b/parse-options.c
index 4fbe924a5..ba6cc30b2 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -40,7 +40,7 @@ static void fix_filename(const char *prefix, const char **file)
 	if (!file || !*file || !prefix || is_absolute_path(*file)
 	    || !strcmp("-", *file))
 		return;
-	*file = xstrdup(prefix_filename(prefix, strlen(prefix), *file));
+	*file = xstrdup(prefix_filename(prefix, *file));
 }
 
 static int opt_command_mode_error(const struct option *opt,
diff --git a/setup.c b/setup.c
index 64f922a93..a76379e0c 100644
--- a/setup.c
+++ b/setup.c
@@ -142,7 +142,7 @@ int check_filename(const char *prefix, const char *arg)
 			return 1;
 		name = arg + 2;
 	} else if (prefix)
-		name = prefix_filename(prefix, strlen(prefix), arg);
+		name = prefix_filename(prefix, arg);
 	else
 		name = arg;
 	if (!lstat(name, &st))
diff --git a/worktree.c b/worktree.c
index fa7bc67a5..42dd3d52b 100644
--- a/worktree.c
+++ b/worktree.c
@@ -254,7 +254,7 @@ struct worktree *find_worktree(struct worktree **list,
 	if ((wt = find_worktree_by_suffix(list, arg)))
 		return wt;
 
-	arg = prefix_filename(prefix, strlen(prefix), arg);
+	arg = prefix_filename(prefix, arg);
 	path = real_pathdup(arg, 1);
 	for (; *list; list++)
 		if (!fspathcmp(path, real_path((*list)->path)))
-- 
2.12.1.683.gcd02edfec


^ permalink raw reply	[flat|threaded] 11+ messages in thread

* [PATCH 4/6] prefix_filename: return newly allocated string
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
                   ` (2 preceding siblings ...)
  2017-03-21  1:22 ` [PATCH 3/6] prefix_filename: drop length parameter Jeff King
@ 2017-03-21  1:28 ` Jeff King
  2017-03-21 18:14   ` Junio C Hamano
  2017-03-21  1:30 ` [PATCH 5/6] prefix_filename: simplify windows #ifdef Jeff King
                   ` (2 subsequent siblings)
  6 siblings, 1 reply; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:28 UTC (permalink / raw)
  To: git

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 <peff@peff.net>
---
 abspath.c             | 10 ++++------
 apply.c               |  9 ++++++---
 builtin/config.c      |  3 +--
 builtin/hash-object.c |  2 +-
 builtin/log.c         |  2 +-
 builtin/mailinfo.c    | 11 ++---------
 builtin/merge-file.c  | 14 +++++++++++---
 builtin/rev-parse.c   |  4 +++-
 builtin/worktree.c    |  3 ++-
 cache.h               |  6 +++---
 diff-no-index.c       |  2 +-
 diff.c                |  6 +++---
 parse-options.c       |  2 +-
 setup.c               | 11 ++++++++---
 worktree.c            |  5 ++++-
 15 files changed, 51 insertions(+), 39 deletions(-)

diff --git a/abspath.c b/abspath.c
index c6f480993..4addd1fde 100644
--- a/abspath.c
+++ b/abspath.c
@@ -246,20 +246,18 @@ char *absolute_pathdup(const char *path)
 	return strbuf_detach(&sb, NULL);
 }
 
-const char *prefix_filename(const char *pfx, const char *arg)
+char *prefix_filename(const char *pfx, const char *arg)
 {
-	static struct strbuf path = STRBUF_INIT;
+	struct strbuf path = STRBUF_INIT;
 	size_t pfx_len = pfx ? strlen(pfx) : 0;
 
 #ifndef GIT_WINDOWS_NATIVE
 	if (!pfx_len || is_absolute_path(arg))
-		return arg;
-	strbuf_reset(&path);
+		return xstrdup(arg);
 	strbuf_add(&path, pfx, pfx_len);
 	strbuf_addstr(&path, arg);
 #else
 	/* don't add prefix to absolute paths, but still replace '\' by '/' */
-	strbuf_reset(&path);
 	if (is_absolute_path(arg))
 		pfx_len = 0;
 	else if (pfx_len)
@@ -267,5 +265,5 @@ const char *prefix_filename(const char *pfx, const char *arg)
 	strbuf_addstr(&path, arg);
 	convert_slashes(path.buf + pfx_len);
 #endif
-	return path.buf;
+	return strbuf_detach(&path, NULL);
 }
diff --git a/apply.c b/apply.c
index b8bd5a4be..e6dbab26a 100644
--- a/apply.c
+++ b/apply.c
@@ -2046,7 +2046,7 @@ static void prefix_one(struct apply_state *state, char **name)
 	char *old_name = *name;
 	if (!old_name)
 		return;
-	*name = xstrdup(prefix_filename(state->prefix, *name));
+	*name = prefix_filename(state->prefix, *name);
 	free(old_name);
 }
 
@@ -4805,6 +4805,7 @@ int apply_all_patches(struct apply_state *state,
 
 	for (i = 0; i < argc; i++) {
 		const char *arg = argv[i];
+		char *to_free = NULL;
 		int fd;
 
 		if (!strcmp(arg, "-")) {
@@ -4814,19 +4815,21 @@ int apply_all_patches(struct apply_state *state,
 			errs |= res;
 			read_stdin = 0;
 			continue;
-		} else if (0 < state->prefix_length)
-			arg = prefix_filename(state->prefix, arg);
+		} else
+			arg = to_free = prefix_filename(state->prefix, arg);
 
 		fd = open(arg, O_RDONLY);
 		if (fd < 0) {
 			error(_("can't open patch '%s': %s"), arg, strerror(errno));
 			res = -128;
+			free(to_free);
 			goto end;
 		}
 		read_stdin = 0;
 		set_default_whitespace_mode(state);
 		res = apply_patch(state, fd, arg, options);
 		close(fd);
+		free(to_free);
 		if (res < 0)
 			goto end;
 		errs |= res;
diff --git a/builtin/config.c b/builtin/config.c
index 74f6c34d1..4f49a0edb 100644
--- a/builtin/config.c
+++ b/builtin/config.c
@@ -527,8 +527,7 @@ int cmd_config(int argc, const char **argv, const char *prefix)
 	else if (given_config_source.file) {
 		if (!is_absolute_path(given_config_source.file) && prefix)
 			given_config_source.file =
-				xstrdup(prefix_filename(prefix,
-							given_config_source.file));
+				prefix_filename(prefix, given_config_source.file);
 	}
 
 	if (respect_includes == -1)
diff --git a/builtin/hash-object.c b/builtin/hash-object.c
index 2ea36909d..bbeaf20bc 100644
--- a/builtin/hash-object.c
+++ b/builtin/hash-object.c
@@ -145,7 +145,7 @@ int cmd_hash_object(int argc, const char **argv, const char *prefix)
 		char *to_free = NULL;
 
 		if (prefix)
-			arg = to_free = xstrdup(prefix_filename(prefix, arg));
+			arg = to_free = prefix_filename(prefix, arg);
 		hash_object(arg, type, no_filters ? NULL : vpath ? vpath : arg,
 			    flags, literally);
 		free(to_free);
diff --git a/builtin/log.c b/builtin/log.c
index bfdc7a23d..670229cbb 100644
--- a/builtin/log.c
+++ b/builtin/log.c
@@ -1084,7 +1084,7 @@ static const char *set_outdir(const char *prefix, const char *output_directory)
 	if (!output_directory)
 		return prefix;
 
-	return xstrdup(prefix_filename(prefix, output_directory));
+	return prefix_filename(prefix, output_directory);
 }
 
 static const char * const builtin_format_patch_usage[] = {
diff --git a/builtin/mailinfo.c b/builtin/mailinfo.c
index 681f07f54..cfb667a59 100644
--- a/builtin/mailinfo.c
+++ b/builtin/mailinfo.c
@@ -11,13 +11,6 @@
 static const char mailinfo_usage[] =
 	"git mailinfo [-k | -b] [-m | --message-id] [-u | --encoding=<encoding> | -n] [--scissors | --no-scissors] <msg> <patch> < mail >info";
 
-static char *prefix_copy(const char *prefix, const char *filename)
-{
-	if (!prefix || is_absolute_path(filename))
-		return xstrdup(filename);
-	return xstrdup(prefix_filename(prefix, filename));
-}
-
 int cmd_mailinfo(int argc, const char **argv, const char *prefix)
 {
 	const char *def_charset;
@@ -60,8 +53,8 @@ int cmd_mailinfo(int argc, const char **argv, const char *prefix)
 	mi.input = stdin;
 	mi.output = stdout;
 
-	msgfile = prefix_copy(prefix, argv[1]);
-	patchfile = prefix_copy(prefix, argv[2]);
+	msgfile = prefix_filename(prefix, argv[1]);
+	patchfile = prefix_filename(prefix, argv[2]);
 
 	status = !!mailinfo(&mi, msgfile, patchfile);
 	clear_mailinfo(&mi);
diff --git a/builtin/merge-file.c b/builtin/merge-file.c
index 63cd94358..47dde7c39 100644
--- a/builtin/merge-file.c
+++ b/builtin/merge-file.c
@@ -65,11 +65,18 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 	}
 
 	for (i = 0; i < 3; i++) {
-		const char *fname = prefix_filename(prefix, argv[i]);
+		char *fname;
+		int ret;
+
 		if (!names[i])
 			names[i] = argv[i];
-		if (read_mmfile(mmfs + i, fname))
+
+		fname = prefix_filename(prefix, argv[i]);
+		ret = read_mmfile(mmfs + i, fname);
+		free(fname);
+		if (ret)
 			return -1;
+
 		if (mmfs[i].size > MAX_XDIFF_SIZE ||
 		    buffer_is_binary(mmfs[i].ptr, mmfs[i].size))
 			return error("Cannot merge binary files: %s",
@@ -86,7 +93,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 
 	if (ret >= 0) {
 		const char *filename = argv[0];
-		const char *fpath = prefix_filename(prefix, argv[0]);
+		char *fpath = prefix_filename(prefix, argv[0]);
 		FILE *f = to_stdout ? stdout : fopen(fpath, "wb");
 
 		if (!f)
@@ -98,6 +105,7 @@ int cmd_merge_file(int argc, const char **argv, const char *prefix)
 		else if (fclose(f))
 			ret = error_errno("Could not close %s", filename);
 		free(result.ptr);
+		free(fpath);
 	}
 
 	if (ret > 127)
diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
index c8035331e..7cd01c281 100644
--- a/builtin/rev-parse.c
+++ b/builtin/rev-parse.c
@@ -228,7 +228,9 @@ static int show_file(const char *arg, int output_prefix)
 	if ((filter & (DO_NONFLAGS|DO_NOREV)) == (DO_NONFLAGS|DO_NOREV)) {
 		if (output_prefix) {
 			const char *prefix = startup_info->prefix;
-			show(prefix_filename(prefix, arg));
+			char *fname = prefix_filename(prefix, arg);
+			show(fname);
+			free(fname);
 		} else
 			show(arg);
 		return 1;
diff --git a/builtin/worktree.c b/builtin/worktree.c
index e38325e44..9993ded41 100644
--- a/builtin/worktree.c
+++ b/builtin/worktree.c
@@ -318,7 +318,8 @@ static int add(int ac, const char **av, const char *prefix)
 {
 	struct add_opts opts;
 	const char *new_branch_force = NULL;
-	const char *path, *branch;
+	char *path;
+	const char *branch;
 	struct option options[] = {
 		OPT__FORCE(&opts.force, N_("checkout <branch> even if already checked out in other worktree")),
 		OPT_STRING('b', NULL, &opts.new_branch, N_("branch"),
diff --git a/cache.h b/cache.h
index 0b53aef0e..aa6a0fb91 100644
--- a/cache.h
+++ b/cache.h
@@ -537,10 +537,10 @@ extern char *prefix_path_gently(const char *prefix, int len, int *remaining, con
  * not have to interact with index entry; i.e. name of a random file
  * on the filesystem.
  *
- * The return value may point to static storage which will be overwritten by
- * further calls.
+ * The return value is always a newly allocated string (even if the
+ * prefix was empty).
  */
-extern const char *prefix_filename(const char *prefix, const char *path);
+extern char *prefix_filename(const char *prefix, const char *path);
 
 extern int check_filename(const char *prefix, const char *name);
 extern void verify_filename(const char *prefix,
diff --git a/diff-no-index.c b/diff-no-index.c
index 5f7317ced..79229382b 100644
--- a/diff-no-index.c
+++ b/diff-no-index.c
@@ -266,7 +266,7 @@ void diff_no_index(struct rev_info *revs,
 			 */
 			p = file_from_standard_input;
 		else if (prefix)
-			p = xstrdup(prefix_filename(prefix, p));
+			p = prefix_filename(prefix, p);
 		paths[i] = p;
 	}
 
diff --git a/diff.c b/diff.c
index 70870b4b6..58cb72d7e 100644
--- a/diff.c
+++ b/diff.c
@@ -4023,8 +4023,7 @@ int diff_opt_parse(struct diff_options *options,
 	else if (!strcmp(arg, "--pickaxe-regex"))
 		options->pickaxe_opts |= DIFF_PICKAXE_REGEX;
 	else if ((argcount = short_opt('O', av, &optarg))) {
-		const char *path = prefix_filename(prefix, optarg);
-		options->orderfile = xstrdup(path);
+		options->orderfile = prefix_filename(prefix, optarg);
 		return argcount;
 	}
 	else if ((argcount = parse_long_opt("diff-filter", av, &optarg))) {
@@ -4071,13 +4070,14 @@ int diff_opt_parse(struct diff_options *options,
 	else if (!strcmp(arg, "--no-function-context"))
 		DIFF_OPT_CLR(options, FUNCCONTEXT);
 	else if ((argcount = parse_long_opt("output", av, &optarg))) {
-		const char *path = prefix_filename(prefix, optarg);
+		char *path = prefix_filename(prefix, optarg);
 		options->file = fopen(path, "w");
 		if (!options->file)
 			die_errno("Could not open '%s'", path);
 		options->close_file = 1;
 		if (options->use_color != GIT_COLOR_ALWAYS)
 			options->use_color = GIT_COLOR_NEVER;
+		free(path);
 		return argcount;
 	} else
 		return 0;
diff --git a/parse-options.c b/parse-options.c
index ba6cc30b2..a23a1e67f 100644
--- a/parse-options.c
+++ b/parse-options.c
@@ -40,7 +40,7 @@ static void fix_filename(const char *prefix, const char **file)
 	if (!file || !*file || !prefix || is_absolute_path(*file)
 	    || !strcmp("-", *file))
 		return;
-	*file = xstrdup(prefix_filename(prefix, *file));
+	*file = prefix_filename(prefix, *file);
 }
 
 static int opt_command_mode_error(const struct option *opt,
diff --git a/setup.c b/setup.c
index a76379e0c..5c7946d2b 100644
--- a/setup.c
+++ b/setup.c
@@ -135,6 +135,7 @@ int path_inside_repo(const char *prefix, const char *path)
 int check_filename(const char *prefix, const char *arg)
 {
 	const char *name;
+	char *to_free = NULL;
 	struct stat st;
 
 	if (starts_with(arg, ":/")) {
@@ -142,13 +143,17 @@ int check_filename(const char *prefix, const char *arg)
 			return 1;
 		name = arg + 2;
 	} else if (prefix)
-		name = prefix_filename(prefix, arg);
+		name = to_free = prefix_filename(prefix, arg);
 	else
 		name = arg;
-	if (!lstat(name, &st))
+	if (!lstat(name, &st)) {
+		free(to_free);
 		return 1; /* file exists */
-	if (errno == ENOENT || errno == ENOTDIR)
+	}
+	if (errno == ENOENT || errno == ENOTDIR) {
+		free(to_free);
 		return 0; /* file does not exist */
+	}
 	die_errno("failed to stat '%s'", arg);
 }
 
diff --git a/worktree.c b/worktree.c
index 42dd3d52b..2520fc65c 100644
--- a/worktree.c
+++ b/worktree.c
@@ -250,16 +250,19 @@ struct worktree *find_worktree(struct worktree **list,
 {
 	struct worktree *wt;
 	char *path;
+	char *to_free;
 
 	if ((wt = find_worktree_by_suffix(list, arg)))
 		return wt;
 
-	arg = prefix_filename(prefix, arg);
+	if (prefix)
+		arg = to_free = prefix_filename(prefix, arg);
 	path = real_pathdup(arg, 1);
 	for (; *list; list++)
 		if (!fspathcmp(path, real_path((*list)->path)))
 			break;
 	free(path);
+	free(to_free);
 	return *list;
 }
 
-- 
2.12.1.683.gcd02edfec


^ permalink raw reply	[flat|threaded] 11+ messages in thread

* [PATCH 5/6] prefix_filename: simplify windows #ifdef
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
                   ` (3 preceding siblings ...)
  2017-03-21  1:28 ` [PATCH 4/6] prefix_filename: return newly allocated string Jeff King
@ 2017-03-21  1:30 ` Jeff King
  2017-03-21  1:31 ` [PATCH 6/6] bundle: use prefix_filename with bundle path Jeff King
  2017-03-21 17:53 ` [PATCH 0/6] prefix_filename cleanups Junio C Hamano
  6 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:30 UTC (permalink / raw)
  To: git

The prefix_filename function used to do an early return when
there was no prefix on non-Windows platforms, but always
allocated on Windows so that it could call convert_slashes().

Now that the function always allocates, we can unify the
logic and make convert_slashes() the only conditional part.

Signed-off-by: Jeff King <peff@peff.net>
---
I wondered here if a compiler might complain about the dead assignment
to pfx_len in the is_absolute_path() conditional. On Windows, that's
used as an offset for calling into convert_slashes(), but on other
platforms we never look at it again.

However, neither gcc nor clang complained, so I'm inclined to go with
what I have here.

 abspath.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/abspath.c b/abspath.c
index 4addd1fde..7f1cfe979 100644
--- a/abspath.c
+++ b/abspath.c
@@ -251,18 +251,15 @@ char *prefix_filename(const char *pfx, const char *arg)
 	struct strbuf path = STRBUF_INIT;
 	size_t pfx_len = pfx ? strlen(pfx) : 0;
 
-#ifndef GIT_WINDOWS_NATIVE
-	if (!pfx_len || is_absolute_path(arg))
-		return xstrdup(arg);
-	strbuf_add(&path, pfx, pfx_len);
-	strbuf_addstr(&path, arg);
-#else
-	/* don't add prefix to absolute paths, but still replace '\' by '/' */
-	if (is_absolute_path(arg))
+	if (!pfx_len)
+		; /* nothing to prefix */
+	else if (is_absolute_path(arg))
 		pfx_len = 0;
-	else if (pfx_len)
+	else
 		strbuf_add(&path, pfx, pfx_len);
+
 	strbuf_addstr(&path, arg);
+#ifdef GIT_WINDOWS_NATIVE
 	convert_slashes(path.buf + pfx_len);
 #endif
 	return strbuf_detach(&path, NULL);
-- 
2.12.1.683.gcd02edfec


^ permalink raw reply	[flat|threaded] 11+ messages in thread

* [PATCH 6/6] bundle: use prefix_filename with bundle path
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
                   ` (4 preceding siblings ...)
  2017-03-21  1:30 ` [PATCH 5/6] prefix_filename: simplify windows #ifdef Jeff King
@ 2017-03-21  1:31 ` Jeff King
  2017-03-21 17:53 ` [PATCH 0/6] prefix_filename cleanups Junio C Hamano
  6 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21  1:31 UTC (permalink / raw)
  To: git

We may take the path to a bundle file as an argument, and
need to adjust the filename based on the prefix we
discovered while setting up the git directory. We do so
manually into a fixed-size buffer, but using
prefix_filename() is the normal way.

Besides being more concise, there are two subtle
improvements:

  1. The original inserted a "/" between the two paths, even
     though the "prefix" argument always has the "/"
     appended. That means that:

       cd subdir && git bundle verify ../foo.bundle

     was looking at (and reporting) subdir//../foo.bundle.
     Harmless, but ugly.  Using prefix_filename() gets this
     right.

  2. The original checked for an absolute path by looking
     for a leading '/'. It should have been using
     is_absolute_path(), which also covers more cases on
     Windows (backslashes and dos drive prefixes).

     But it's easier still to just pass the name to
     prefix_filename(), which handles this case
     automatically.

Note that we'll just leak the resulting buffer in the name
of simplicity, since it needs to last through the duration
of the program anyway.

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/bundle.c | 8 +-------
 1 file changed, 1 insertion(+), 7 deletions(-)

diff --git a/builtin/bundle.c b/builtin/bundle.c
index 4883a435a..d0de59b94 100644
--- a/builtin/bundle.c
+++ b/builtin/bundle.c
@@ -20,21 +20,15 @@ int cmd_bundle(int argc, const char **argv, const char *prefix)
 	struct bundle_header header;
 	const char *cmd, *bundle_file;
 	int bundle_fd = -1;
-	char buffer[PATH_MAX];
 
 	if (argc < 3)
 		usage(builtin_bundle_usage);
 
 	cmd = argv[1];
-	bundle_file = argv[2];
+	bundle_file = prefix_filename(prefix, argv[2]);
 	argc -= 2;
 	argv += 2;
 
-	if (prefix && bundle_file[0] != '/') {
-		snprintf(buffer, sizeof(buffer), "%s/%s", prefix, bundle_file);
-		bundle_file = buffer;
-	}
-
 	memset(&header, 0, sizeof(header));
 	if (strcmp(cmd, "create") && (bundle_fd =
 				read_bundle_header(bundle_file, &header)) < 0)
-- 
2.12.1.683.gcd02edfec

^ permalink raw reply	[flat|threaded] 11+ messages in thread

* Re: [PATCH 0/6] prefix_filename cleanups
  2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
                   ` (5 preceding siblings ...)
  2017-03-21  1:31 ` [PATCH 6/6] bundle: use prefix_filename with bundle path Jeff King
@ 2017-03-21 17:53 ` Junio C Hamano
  6 siblings, 0 replies; 11+ messages in thread
From: Junio C Hamano @ 2017-03-21 17:53 UTC (permalink / raw)
  To: Jeff King; +Cc: git

Jeff King <peff@peff.net> writes:

> I noticed a spot in builtin/bundle.c that would benefit from using
> prefix_filename(). But when I tried to use it, I noticed its interface
> was a little error-prone (because it returns a static buffer). And
> indeed, a little digging found a bug in hash-object related to this.
>
> So here's the fix for the hash-object bug, some cleanups to make such
> bugs less likely, and then finally the bundle conversion. The bundle
> thing does fix some minor bugs. It _could_ come before the cleanups if
> we wanted to float the fixes to the top, but the function is much more
> pleasant to call after the cleanups. :)

Thanks.  They all looked sensible.

^ permalink raw reply	[flat|threaded] 11+ messages in thread

* Re: [PATCH 4/6] prefix_filename: return newly allocated string
  2017-03-21  1:28 ` [PATCH 4/6] prefix_filename: return newly allocated string Jeff King
@ 2017-03-21 18:14   ` Junio C Hamano
  2017-03-21 18:23     ` Jeff King
  0 siblings, 1 reply; 11+ messages in thread
From: Junio C Hamano @ 2017-03-21 18:14 UTC (permalink / raw)
  To: Jeff King; +Cc: git

Jeff King <peff@peff.net> writes:

> diff --git a/worktree.c b/worktree.c
> index 42dd3d52b..2520fc65c 100644
> --- a/worktree.c
> +++ b/worktree.c
> @@ -250,16 +250,19 @@ struct worktree *find_worktree(struct worktree **list,
>  {
>  	struct worktree *wt;
>  	char *path;
> +	char *to_free;
>  
>  	if ((wt = find_worktree_by_suffix(list, arg)))
>  		return wt;
>  
> -	arg = prefix_filename(prefix, arg);
> +	if (prefix)
> +		arg = to_free = prefix_filename(prefix, arg);
>  	path = real_pathdup(arg, 1);
>  	for (; *list; list++)
>  		if (!fspathcmp(path, real_path((*list)->path)))
>  			break;
>  	free(path);
> +	free(to_free);
>  	return *list;
>  }

worktree.c:265:6: error: to_free may be used uninitialized in this function
---
 worktree.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/worktree.c b/worktree.c
index 2520fc65cc..bae787cf8d 100644
--- a/worktree.c
+++ b/worktree.c
@@ -250,7 +250,7 @@ struct worktree *find_worktree(struct worktree **list,
 {
 	struct worktree *wt;
 	char *path;
-	char *to_free;
+	char *to_free = NULL;
 
 	if ((wt = find_worktree_by_suffix(list, arg)))
 		return wt;
-- 
2.12.1-382-gc0f9c70589


^ permalink raw reply	[flat|threaded] 11+ messages in thread

* Re: [PATCH 4/6] prefix_filename: return newly allocated string
  2017-03-21 18:14   ` Junio C Hamano
@ 2017-03-21 18:23     ` Jeff King
  2017-03-21 23:32       ` Jeff King
  0 siblings, 1 reply; 11+ messages in thread
From: Jeff King @ 2017-03-21 18:23 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Tue, Mar 21, 2017 at 11:14:23AM -0700, Junio C Hamano wrote:

> Jeff King <peff@peff.net> writes:
> 
> > diff --git a/worktree.c b/worktree.c
> > index 42dd3d52b..2520fc65c 100644
> > --- a/worktree.c
> > +++ b/worktree.c
> > @@ -250,16 +250,19 @@ struct worktree *find_worktree(struct worktree **list,
> >  {
> >  	struct worktree *wt;
> >  	char *path;
> > +	char *to_free;
> >  
> >  	if ((wt = find_worktree_by_suffix(list, arg)))
> >  		return wt;
> >  
> > -	arg = prefix_filename(prefix, arg);
> > +	if (prefix)
> > +		arg = to_free = prefix_filename(prefix, arg);
> >  	path = real_pathdup(arg, 1);
> >  	for (; *list; list++)
> >  		if (!fspathcmp(path, real_path((*list)->path)))
> >  			break;
> >  	free(path);
> > +	free(to_free);
> >  	return *list;
> >  }
> 
> worktree.c:265:6: error: to_free may be used uninitialized in this function

Doh. I had originally written it without the "if (prefix)" and added it
as a micro-optimization at the end.

Still, the whole thing compiles fine for me. I find it odd that neither
gcc nor clang notices the problem on my system. It's quite obviously
wrong.

> diff --git a/worktree.c b/worktree.c
> index 2520fc65cc..bae787cf8d 100644
> --- a/worktree.c
> +++ b/worktree.c
> @@ -250,7 +250,7 @@ struct worktree *find_worktree(struct worktree **list,
>  {
>  	struct worktree *wt;
>  	char *path;
> -	char *to_free;
> +	char *to_free = NULL;

Yep, this is the right fix. Thanks.

-Peff

^ permalink raw reply	[flat|threaded] 11+ messages in thread

* Re: [PATCH 4/6] prefix_filename: return newly allocated string
  2017-03-21 18:23     ` Jeff King
@ 2017-03-21 23:32       ` Jeff King
  0 siblings, 0 replies; 11+ messages in thread
From: Jeff King @ 2017-03-21 23:32 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Tue, Mar 21, 2017 at 02:23:35PM -0400, Jeff King wrote:

> > worktree.c:265:6: error: to_free may be used uninitialized in this function
> 
> Doh. I had originally written it without the "if (prefix)" and added it
> as a micro-optimization at the end.
> 
> Still, the whole thing compiles fine for me. I find it odd that neither
> gcc nor clang notices the problem on my system. It's quite obviously
> wrong.

Ah, I found it; it is only triggered with -O2. I usually compile with
-O0 during my edit/compile/test cycles.

-Peff

^ permalink raw reply	[flat|threaded] 11+ messages in thread

end of thread, back to index

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-21  1:18 [PATCH 0/6] prefix_filename cleanups Jeff King
2017-03-21  1:20 ` [PATCH 1/6] hash-object: fix buffer reuse with --path in a subdirectory Jeff King
2017-03-21  1:21 ` [PATCH 2/6] prefix_filename: move docstring to header file Jeff King
2017-03-21  1:22 ` [PATCH 3/6] prefix_filename: drop length parameter Jeff King
2017-03-21  1:28 ` [PATCH 4/6] prefix_filename: return newly allocated string Jeff King
2017-03-21 18:14   ` Junio C Hamano
2017-03-21 18:23     ` Jeff King
2017-03-21 23:32       ` Jeff King
2017-03-21  1:30 ` [PATCH 5/6] prefix_filename: simplify windows #ifdef Jeff King
2017-03-21  1:31 ` [PATCH 6/6] bundle: use prefix_filename with bundle path Jeff King
2017-03-21 17:53 ` [PATCH 0/6] prefix_filename cleanups Junio C Hamano

git@vger.kernel.org mailing list mirror (one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/
       or Tor2web: https://www.tor2web.org/

AGPL code for this site: git clone https://public-inbox.org/ public-inbox