git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v6 01/32] path.c: make get_pathname() return strbuf instead of static buffer

From
Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Date
Jul 9, 2014, 07:32 UTC
Message-ID
<1404891197-18067-2-git-send-email-pclouds@gmail.com>
In-Reply-To
<1404891197-18067-1-git-send-email-pclouds@gmail.com>

We've been avoiding PATH_MAX whenever possible. This patch makes get_pathname() return a strbuf and updates the callers to take advantage of this. The code is simplified as we no longer need to worry about buffer overflow.

vsnpath() behavior is changed slightly: previously it always clears the buffer before writing, now it just appends. Fortunately this is a static function and all of its callers prepare the buffer properly: git_path() gets the buffer from get_pathname() which resets the buffer, the remaining call sites start with STRBUF_INIT'd buffer.

Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
---
 path.c | 120 ++++++++++++++++++++++++++++-------------------------------------
 1 file changed, 51 insertions(+), 69 deletions(-)
diff --git a/path.c b/path.c
index bc804a3..42ef3af 100644
--- a/path.c
+++ b/path.c
@@ -16,11 +16,15 @@ static int get_st_mode_bits(const char *path, int *mode)
 
 static char bad_path[] = "/bad-path/";
 
-static char *get_pathname(void)
+static struct strbuf *get_pathname(void)
 {
-	static char pathname_array[4][PATH_MAX];
+	static struct strbuf pathname_array[4] = {
+		STRBUF_INIT, STRBUF_INIT, STRBUF_INIT, STRBUF_INIT
+	};
 	static int index;
-	return pathname_array[3 & ++index];
+	struct strbuf *sb = &pathname_array[3 & ++index];
+	strbuf_reset(sb);
+	return sb;
 }
 
 static char *cleanup_path(char *path)
@@ -34,6 +38,13 @@ static char *cleanup_path(char *path)
 	return path;
 }
 
+static void strbuf_cleanup_path(struct strbuf *sb)
+{
+	char *path = cleanup_path(sb->buf);
+	if (path > sb->buf)
+		strbuf_remove(sb, 0, path - sb->buf);
+}
+
 char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 {
 	va_list args;
@@ -49,85 +60,70 @@ char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 	return cleanup_path(buf);
 }
 
-static char *vsnpath(char *buf, size_t n, const char *fmt, va_list args)
+static void vsnpath(struct strbuf *buf, const char *fmt, va_list args)
 {
 	const char *git_dir = get_git_dir();
-	size_t len;
-
-	len = strlen(git_dir);
-	if (n < len + 1)
-		goto bad;
-	memcpy(buf, git_dir, len);
-	if (len && !is_dir_sep(git_dir[len-1]))
-		buf[len++] = '/';
-	len += vsnprintf(buf + len, n - len, fmt, args);
-	if (len >= n)
-		goto bad;
-	return cleanup_path(buf);
-bad:
-	strlcpy(buf, bad_path, n);
-	return buf;
+	strbuf_addstr(buf, git_dir);
+	if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
+		strbuf_addch(buf, '/');
+	strbuf_vaddf(buf, fmt, args);
+	strbuf_cleanup_path(buf);
 }
 
 char *git_snpath(char *buf, size_t n, const char *fmt, ...)
 {
-	char *ret;
+	struct strbuf sb = STRBUF_INIT;
 	va_list args;
 	va_start(args, fmt);
-	ret = vsnpath(buf, n, fmt, args);
+	vsnpath(&sb, fmt, args);
 	va_end(args);
-	return ret;
+	if (sb.len >= n)
+		strlcpy(buf, bad_path, n);
+	else
+		memcpy(buf, sb.buf, sb.len + 1);
+	strbuf_release(&sb);
+	return buf;
 }
 
 char *git_pathdup(const char *fmt, ...)
 {
-	char path[PATH_MAX], *ret;
+	struct strbuf path = STRBUF_INIT;
 	va_list args;
 	va_start(args, fmt);
-	ret = vsnpath(path, sizeof(path), fmt, args);
+	vsnpath(&path, fmt, args);
 	va_end(args);
-	return xstrdup(ret);
+	return strbuf_detach(&path, NULL);
 }
 
 char *mkpathdup(const char *fmt, ...)
 {
-	char *path;
 	struct strbuf sb = STRBUF_INIT;
 	va_list args;
-
 	va_start(args, fmt);
 	strbuf_vaddf(&sb, fmt, args);
 	va_end(args);
-	path = xstrdup(cleanup_path(sb.buf));
-
-	strbuf_release(&sb);
-	return path;
+	strbuf_cleanup_path(&sb);
+	return strbuf_detach(&sb, NULL);
 }
 
 char *mkpath(const char *fmt, ...)
 {
 	va_list args;
-	unsigned len;
-	char *pathname = get_pathname();
-
+	struct strbuf *pathname = get_pathname();
 	va_start(args, fmt);
-	len = vsnprintf(pathname, PATH_MAX, fmt, args);
+	strbuf_vaddf(pathname, fmt, args);
 	va_end(args);
-	if (len >= PATH_MAX)
-		return bad_path;
-	return cleanup_path(pathname);
+	return cleanup_path(pathname->buf);
 }
 
 char *git_path(const char *fmt, ...)
 {
-	char *pathname = get_pathname();
+	struct strbuf *pathname = get_pathname();
 	va_list args;
-	char *ret;
-
 	va_start(args, fmt);
-	ret = vsnpath(pathname, PATH_MAX, fmt, args);
+	vsnpath(pathname, fmt, args);
 	va_end(args);
-	return ret;
+	return pathname->buf;
 }
 
 void home_config_paths(char **global, char **xdg, char *file)
@@ -158,41 +154,27 @@ void home_config_paths(char **global, char **xdg, char *file)
 
 char *git_path_submodule(const char *path, const char *fmt, ...)
 {
-	char *pathname = get_pathname();
-	struct strbuf buf = STRBUF_INIT;
+	struct strbuf *buf = get_pathname();
 	const char *git_dir;
 	va_list args;
-	unsigned len;
-
-	len = strlen(path);
-	if (len > PATH_MAX-100)
-		return bad_path;
 
-	strbuf_addstr(&buf, path);
-	if (len && path[len-1] != '/')
-		strbuf_addch(&buf, '/');
-	strbuf_addstr(&buf, ".git");
+	strbuf_addstr(buf, path);
+	if (buf->len && buf->buf[buf->len - 1] != '/')
+		strbuf_addch(buf, '/');
+	strbuf_addstr(buf, ".git");
 
-	git_dir = read_gitfile(buf.buf);
+	git_dir = read_gitfile(buf->buf);
 	if (git_dir) {
-		strbuf_reset(&buf);
-		strbuf_addstr(&buf, git_dir);
+		strbuf_reset(buf);
+		strbuf_addstr(buf, git_dir);
 	}
-	strbuf_addch(&buf, '/');
-
-	if (buf.len >= PATH_MAX)
-		return bad_path;
-	memcpy(pathname, buf.buf, buf.len + 1);
-
-	strbuf_release(&buf);
-	len = strlen(pathname);
+	strbuf_addch(buf, '/');
 
 	va_start(args, fmt);
-	len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
+	strbuf_vaddf(buf, fmt, args);
 	va_end(args);
-	if (len >= PATH_MAX)
-		return bad_path;
-	return cleanup_path(pathname);
+	strbuf_cleanup_path(buf);
+	return buf->buf;
 }
 
 int validate_headref(const char *path)
-- 
1.9.1.346.ga2b5940
Previous: Nguyễn Thái Ngọc DuyNext: Nguyễn Thái Ngọc Duy
Message 2 of 83 in “Support multiple checkouts”
  1. 00/32 Support multiple checkoutsNguyễn Thái Ngọc Duy, Jul 9, 2014
  2. 01/32 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Jul 9, 2014
  3. 02/32 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Jul 9, 2014
  4. 03/32 git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy, Jul 9, 2014
  5. 04/32 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Jul 9, 2014
  6. 05/32 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Jul 9, 2014
  7. 06/32 setup_git_env: use git_pathdup instead of xmalloc + sprintfNguyễn Thái Ngọc Duy, Jul 9, 2014
  8. 07/32 setup_git_env(): introduce git_path_from_env() helperNguyễn Thái Ngọc Duy, Jul 9, 2014
  9. 08/32 git_path(): be aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Jul 9, 2014
  10. 09/32 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Jul 9, 2014
  11. 10/32 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Jul 9, 2014
  12. 11/32 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Jul 9, 2014
  13. 12/32 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Jul 9, 2014
  14. 13/32 $GIT_COMMON_DIR: a new environment variableNguyễn Thái Ngọc Duy, Jul 9, 2014
  15. 14/32 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Jul 9, 2014
  16. 15/32 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Jul 9, 2014
  17. 16/32 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Jul 9, 2014
  18. 17/32 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Jul 9, 2014
  19. 18/32 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Jul 9, 2014
  20. 19/32 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Jul 9, 2014
  21. 20/32 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Jul 9, 2014
  22. 21/32 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Jul 9, 2014
  23. 22/32 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Jul 9, 2014
  24. 23/32 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Jul 9, 2014
  25. 24/32 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Jul 9, 2014
  26. 25/32 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Jul 9, 2014
  27. 26/32 checkout: detach if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Jul 9, 2014
  28. Max KirillovJul 12, 2014
  29. 27/32 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Jul 9, 2014
  30. Eric SunshineJul 9, 2014
  31. 28/32 gc: style change -- no SP before closing bracketNguyễn Thái Ngọc Duy, Jul 9, 2014
  32. Eric SunshineJul 9, 2014
  33. Junio C HamanoJul 14, 2014
  34. 29/32 gc: support prune --reposNguyễn Thái Ngọc Duy, Jul 9, 2014
  35. Eric SunshineJul 9, 2014
  36. 30/32 count-objects: report unused files in $GIT_DIR/repos/...Nguyễn Thái Ngọc Duy, Jul 9, 2014
  37. 31/32 git_path(): keep "info/sparse-checkout" per work-treeNguyễn Thái Ngọc Duy, Jul 9, 2014
  38. 32/32 checkout: don't require a work tree when checking out into a new oneNguyễn Thái Ngọc Duy, Jul 9, 2014
  39. Dennis KaarsemakerJul 11, 2014
  40. 00/31 Support multiple checkoutsNguyễn Thái Ngọc Duy, Jul 13, 2014
  41. 01/31 path.c: make get_pathname() return strbuf instead of static bufferNguyễn Thái Ngọc Duy, Jul 13, 2014
  42. 02/31 path.c: make get_pathname() call sites return const char *Nguyễn Thái Ngọc Duy, Jul 13, 2014
  43. 03/31 git_snpath(): retire and replace with strbuf_git_path()Nguyễn Thái Ngọc Duy, Jul 13, 2014
  44. 04/31 path.c: rename vsnpath() to do_git_path()Nguyễn Thái Ngọc Duy, Jul 13, 2014
  45. 05/31 path.c: group git_path(), git_pathdup() and strbuf_git_path() togetherNguyễn Thái Ngọc Duy, Jul 13, 2014
  46. 06/31 git_path(): be aware of file relocation in $GIT_DIRNguyễn Thái Ngọc Duy, Jul 13, 2014
  47. 07/31 *.sh: respect $GIT_INDEX_FILENguyễn Thái Ngọc Duy, Jul 13, 2014
  48. 08/31 reflog: avoid constructing .lock path with git_pathNguyễn Thái Ngọc Duy, Jul 13, 2014
  49. 09/31 fast-import: use git_path() for accessing .git dir instead of get_git_dir()Nguyễn Thái Ngọc Duy, Jul 13, 2014
  50. 10/31 commit: use SEQ_DIR instead of hardcoding "sequencer"Nguyễn Thái Ngọc Duy, Jul 13, 2014
  51. 11/31 $GIT_COMMON_DIR: a new environment variableNguyễn Thái Ngọc Duy, Jul 13, 2014
  52. Eric SunshineJul 23, 2014
  53. 12/31 git-sh-setup.sh: use rev-parse --git-path to get $GIT_DIR/objectsNguyễn Thái Ngọc Duy, Jul 13, 2014
  54. 13/31 *.sh: avoid hardcoding $GIT_DIR/hooks/...Nguyễn Thái Ngọc Duy, Jul 13, 2014
  55. 14/31 git-stash: avoid hardcoding $GIT_DIR/logs/....Nguyễn Thái Ngọc Duy, Jul 13, 2014
  56. 15/31 setup.c: convert is_git_directory() to use strbufNguyễn Thái Ngọc Duy, Jul 13, 2014
  57. 16/31 setup.c: detect $GIT_COMMON_DIR in is_git_directory()Nguyễn Thái Ngọc Duy, Jul 13, 2014
  58. 17/31 setup.c: convert check_repository_format_gently to use strbufNguyễn Thái Ngọc Duy, Jul 13, 2014
  59. 18/31 setup.c: detect $GIT_COMMON_DIR check_repository_format_gently()Nguyễn Thái Ngọc Duy, Jul 13, 2014
  60. 19/31 setup.c: support multi-checkout repo setupNguyễn Thái Ngọc Duy, Jul 13, 2014
  61. 20/31 wrapper.c: wrapper to open a file, fprintf then closeNguyễn Thái Ngọc Duy, Jul 13, 2014
  62. 21/31 use new wrapper write_file() for simple file writingNguyễn Thái Ngọc Duy, Jul 13, 2014
  63. 22/31 checkout: support checking out into a new working directoryNguyễn Thái Ngọc Duy, Jul 13, 2014
  64. Max KirillovJul 17, 2014
  65. Junio C HamanoJul 17, 2014
  66. Eric SunshineJul 18, 2014
  67. 23/31 checkout: clean up half-prepared directories in --to modeNguyễn Thái Ngọc Duy, Jul 13, 2014
  68. Eric SunshineJul 20, 2014
  69. Eric SunshineJul 21, 2014
  70. Duy NguyenJul 23, 2014
  71. 24/31 checkout: detach if the branch is already checked out elsewhereNguyễn Thái Ngọc Duy, Jul 13, 2014
  72. 25/31 prune: strategies for linked checkoutsNguyễn Thái Ngọc Duy, Jul 13, 2014
  73. Thomas RastJul 18, 2014
  74. Duy NguyenJul 19, 2014
  75. 26/31 gc: style change -- no SP before closing bracketNguyễn Thái Ngọc Duy, Jul 13, 2014
  76. 27/31 gc: factor out gc.pruneexpire parsing codeNguyễn Thái Ngọc Duy, Jul 13, 2014
  77. 28/31 gc: support prune --reposNguyễn Thái Ngọc Duy, Jul 13, 2014
  78. 29/31 count-objects: report unused files in $GIT_DIR/repos/...Nguyễn Thái Ngọc Duy, Jul 13, 2014
  79. 30/31 git_path(): keep "info/sparse-checkout" per work-treeNguyễn Thái Ngọc Duy, Jul 13, 2014
  80. 31/31 checkout: don't require a work tree when checking out into a new oneNguyễn Thái Ngọc Duy, Jul 13, 2014
  81. Junio C HamanoJul 14, 2014
  82. Duy NguyenJul 14, 2014
  83. Junio C HamanoJul 14, 2014

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.