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

[PATCH 06/21] convert manual allocations to argv_array

From
Jeff King <peff@peff.net>
Date
Feb 19, 2016, 11:23 UTC
Message-ID
<20160219112324.GF9319@sigill.intra.peff.net>
In-Reply-To
<20160219111941.GA31906@sigill.intra.peff.net>

There are many manual argv allocations that predate the argv_array API. Switching to that API brings a few advantages:

  1. We no longer have to manually compute the correct final
     array size (so it's one less thing we can screw up).
  2. In many cases we had to make a separate pass to count,
     then allocate, then fill in the array. Now we can do it
     in one pass, making the code shorter and easier to
     follow.
  3. argv_array handles memory ownership for us, making it
     more obvious when things should be free()d and and when
     not.

Most of these cases are pretty straightforward. In some, we switch from "run_command_v" to "run_command" which lets us directly use the argv_array embedded in "struct child_process".

Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/grep.c         | 10 +++++-----
 builtin/receive-pack.c | 12 +++---------
 builtin/remote-ext.c   | 26 +++++---------------------
 daemon.c               | 12 +++++-------
 git.c                  | 14 +++++---------
 line-log.c             | 26 ++++++++++----------------
 remote-curl.c          | 23 +++++++++++------------
 7 files changed, 44 insertions(+), 79 deletions(-)
diff --git a/builtin/grep.c b/builtin/grep.c
index 8c516a9..aa7435f 100644
--- a/builtin/grep.c
+++ b/builtin/grep.c
@@ -365,17 +365,17 @@ static void append_path(struct grep_opt *opt, const void *data, size_t len)
 static void run_pager(struct grep_opt *opt, const char *prefix)
 {
 	struct string_list *path_list = opt->output_priv;
-	const char **argv = xmalloc(sizeof(const char *) * (path_list->nr + 1));
+	struct child_process child = CHILD_PROCESS_INIT;
 	int i, status;
 
 	for (i = 0; i < path_list->nr; i++)
-		argv[i] = path_list->items[i].string;
-	argv[path_list->nr] = NULL;
+		argv_array_push(&child.args, path_list->items[i].string);
+	child.dir = prefix;
+	child.use_shell = 1;
 
-	status = run_command_v_opt_cd_env(argv, RUN_USING_SHELL, prefix, NULL);
+	status = run_command(&child);
 	if (status)
 		exit(status);
-	free(argv);
 }
 
 static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
index f2d6761..932afab 100644
--- a/builtin/receive-pack.c
+++ b/builtin/receive-pack.c
@@ -1031,7 +1031,6 @@ static void run_update_post_hook(struct command *commands)
 {
 	struct command *cmd;
 	int argc;
-	const char **argv;
 	struct child_process proc = CHILD_PROCESS_INIT;
 	const char *hook;
 
@@ -1044,21 +1043,16 @@ static void run_update_post_hook(struct command *commands)
 	if (!argc || !hook)
 		return;
 
-	argv = xmalloc(sizeof(*argv) * (2 + argc));
-	argv[0] = hook;
-
-	for (argc = 1, cmd = commands; cmd; cmd = cmd->next) {
+	argv_array_push(&proc.args, hook);
+	for (cmd = commands; cmd; cmd = cmd->next) {
 		if (cmd->error_string || cmd->did_not_exist)
 			continue;
-		argv[argc] = xstrdup(cmd->ref_name);
-		argc++;
+		argv_array_push(&proc.args, cmd->ref_name);
 	}
-	argv[argc] = NULL;
 
 	proc.no_stdin = 1;
 	proc.stdout_to_stderr = 1;
 	proc.err = use_sideband ? -1 : 0;
-	proc.argv = argv;
 
 	if (!start_command(&proc)) {
 		if (use_sideband)
diff --git a/builtin/remote-ext.c b/builtin/remote-ext.c
index e3cd25d..7457c74 100644
--- a/builtin/remote-ext.c
+++ b/builtin/remote-ext.c
@@ -114,30 +114,14 @@ static char *strip_escapes(const char *str, const char *service,
 	}
 }
 
-/* Should be enough... */
-#define MAXARGUMENTS 256
-
-static const char **parse_argv(const char *arg, const char *service)
+static void parse_argv(struct argv_array *out, const char *arg, const char *service)
 {
-	int arguments = 0;
-	int i;
-	const char **ret;
-	char *temparray[MAXARGUMENTS + 1];
-
 	while (*arg) {
-		char *expanded;
-		if (arguments == MAXARGUMENTS)
-			die("remote-ext command has too many arguments");
-		expanded = strip_escapes(arg, service, &arg);
+		char *expanded = strip_escapes(arg, service, &arg);
 		if (expanded)
-			temparray[arguments++] = expanded;
+			argv_array_push(out, expanded);
+		free(expanded);
 	}
-
-	ret = xmalloc((arguments + 1) * sizeof(char *));
-	for (i = 0; i < arguments; i++)
-		ret[i] = temparray[i];
-	ret[arguments] = NULL;
-	return ret;
 }
 
 static void send_git_request(int stdin_fd, const char *serv, const char *repo,
@@ -158,7 +142,7 @@ static int run_child(const char *arg, const char *service)
 	child.in = -1;
 	child.out = -1;
 	child.err = 0;
-	child.argv = parse_argv(arg, service);
+	parse_argv(&child.args, arg, service);
 
 	if (start_command(&child) < 0)
 		die("Can't run specified command");
diff --git a/daemon.c b/daemon.c
index 46b411c..3f57adb 100644
--- a/daemon.c
+++ b/daemon.c
@@ -808,7 +808,7 @@ static void check_dead_children(void)
 			cradle = &blanket->next;
 }
 
-static char **cld_argv;
+struct argv_array cld_argv = ARGV_ARRAY_INIT;
 static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 {
 	struct child_process cld = CHILD_PROCESS_INIT;
@@ -842,7 +842,7 @@ static void handle(int incoming, struct sockaddr *addr, socklen_t addrlen)
 #endif
 	}
 
-	cld.argv = (const char **)cld_argv;
+	cld.argv = cld_argv.argv;
 	cld.in = incoming;
 	cld.out = dup(incoming);
 
@@ -1374,12 +1374,10 @@ int main(int argc, char **argv)
 		write_file(pid_file, "%"PRIuMAX, (uintmax_t) getpid());
 
 	/* prepare argv for serving-processes */
-	cld_argv = xmalloc(sizeof (char *) * (argc + 2));
-	cld_argv[0] = argv[0];	/* git-daemon */
-	cld_argv[1] = "--serve";
+	argv_array_push(&cld_argv, argv[0]); /* git-daemon */
+	argv_array_push(&cld_argv, "--serve");
 	for (i = 1; i < argc; ++i)
-		cld_argv[i+1] = argv[i];
-	cld_argv[argc+1] = NULL;
+		argv_array_push(&cld_argv, argv[i]);
 
 	return serve(&listen_addr, listen_port, cred);
 }
diff --git a/git.c b/git.c
index 6c64c94..087ad31 100644
--- a/git.c
+++ b/git.c
@@ -247,20 +247,16 @@ static int handle_alias(int *argcp, const char ***argv)
 	alias_string = alias_lookup(alias_command);
 	if (alias_string) {
 		if (alias_string[0] == '!') {
-			const char **alias_argv;
-			int argc = *argcp, i;
+			struct child_process child = CHILD_PROCESS_INIT;
 
 			commit_pager_choice();
 			restore_env(1);
 
-			/* build alias_argv */
-			alias_argv = xmalloc(sizeof(*alias_argv) * (argc + 1));
-			alias_argv[0] = alias_string + 1;
-			for (i = 1; i < argc; ++i)
-				alias_argv[i] = (*argv)[i];
-			alias_argv[argc] = NULL;
+			child.use_shell = 1;
+			argv_array_push(&child.args, alias_string + 1);
+			argv_array_pushv(&child.args, (*argv) + 1);
 
-			ret = run_command_v_opt(alias_argv, RUN_USING_SHELL);
+			ret = run_command(&child);
 			if (ret >= 0)   /* normal exit */
 				exit(ret);
 
diff --git a/line-log.c b/line-log.c
index af6e2f7..5942a6f 100644
--- a/line-log.c
+++ b/line-log.c
@@ -14,6 +14,7 @@
 #include "graph.h"
 #include "userdiff.h"
 #include "line-log.h"
+#include "argv-array.h"
 
 static void range_set_grow(struct range_set *rs, size_t extra)
 {
@@ -746,23 +747,16 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list
 	add_line_range(rev, commit, range);
 
 	if (!rev->diffopt.detect_rename) {
-		int i, count = 0;
-		struct line_log_data *r = range;
-		const char **paths;
-		while (r) {
-			count++;
-			r = r->next;
-		}
-		paths = xmalloc((count+1)*sizeof(char *));
-		r = range;
-		for (i = 0; i < count; i++) {
-			paths[i] = xstrdup(r->path);
-			r = r->next;
-		}
-		paths[count] = NULL;
+		struct line_log_data *r;
+		struct argv_array paths = ARGV_ARRAY_INIT;
+
+		for (r = range; r; r = r->next)
+			argv_array_push(&paths, r->path);
 		parse_pathspec(&rev->diffopt.pathspec, 0,
-			       PATHSPEC_PREFER_FULL, "", paths);
-		free(paths);
+			       PATHSPEC_PREFER_FULL, "", paths.argv);
+		/* argv strings are now owned by pathspec */
+		paths.argc = 0;
+		argv_array_clear(&paths);
 	}
 }
 
diff --git a/remote-curl.c b/remote-curl.c
index c704857..42deeec 100644
--- a/remote-curl.c
+++ b/remote-curl.c
@@ -845,23 +845,22 @@ static void parse_fetch(struct strbuf *buf)
 
 static int push_dav(int nr_spec, char **specs)
 {
-	const char **argv = xmalloc((10 + nr_spec) * sizeof(char*));
-	int argc = 0, i;
+	struct child_process child = CHILD_PROCESS_INIT;
+	size_t i;
 
-	argv[argc++] = "http-push";
-	argv[argc++] = "--helper-status";
+	child.git_cmd = 1;
+	argv_array_push(&child.args, "http-push");
+	argv_array_push(&child.args, "--helper-status");
 	if (options.dry_run)
-		argv[argc++] = "--dry-run";
+		argv_array_push(&child.args, "--dry-run");
 	if (options.verbosity > 1)
-		argv[argc++] = "--verbose";
-	argv[argc++] = url.buf;
+		argv_array_push(&child.args, "--verbose");
+	argv_array_push(&child.args, url.buf);
 	for (i = 0; i < nr_spec; i++)
-		argv[argc++] = specs[i];
-	argv[argc++] = NULL;
+		argv_array_push(&child.args, specs[i]);
 
-	if (run_command_v_opt(argv, RUN_GIT_CMD))
-		die("git-%s failed", argv[0]);
-	free(argv);
+	if (run_command(&child))
+		die("git-http-push failed");
 	return 0;
 }
 
-- 
2.7.1.577.gfed91b8
Previous: Jeff KingNext: Eric Sunshine
Message 45 of 93 in “hardening allocations against integer overflow”
  1. 0/18 hardening allocations against integer overflowJeff King, Feb 15, 2016
  2. 01/18 add helpers for detecting size_t overflowJeff King, Feb 15, 2016
  3. 02/18 tree-diff: catch integer overflow in combine_diff_path allocationJeff King, Feb 15, 2016
  4. 03/18 harden REALLOC_ARRAY and xcalloc against size_t overflowJeff King, Feb 15, 2016
  5. 04/18 add helpers for allocating flex-array structsJeff King, Feb 15, 2016
  6. Eric SunshineFeb 16, 2016
  7. Jeff KingFeb 16, 2016
  8. 05/18 convert trivial cases to ALLOC_ARRAYJeff King, Feb 15, 2016
  9. Eric SunshineFeb 16, 2016
  10. Jeff KingFeb 16, 2016
  11. Eric SunshineFeb 16, 2016
  12. Jeff KingFeb 16, 2016
  13. 06/18 use xmallocz to avoid size arithmeticJeff King, Feb 15, 2016
  14. 07/18 convert trivial cases to FLEX_ARRAY macrosJeff King, Feb 15, 2016
  15. Eric SunshineFeb 16, 2016
  16. Jeff KingFeb 16, 2016
  17. Jeff KingFeb 16, 2016
  18. Jeff KingFeb 16, 2016
  19. Eric SunshineFeb 16, 2016
  20. Jeff KingFeb 16, 2016
  21. Eric SunshineFeb 16, 2016
  22. 08/18 use st_add and st_mult for allocation size computationJeff King, Feb 15, 2016
  23. Eric SunshineFeb 16, 2016
  24. 09/18 write_untracked_extension: use FLEX_ALLOC helperJeff King, Feb 15, 2016
  25. 10/18 fast-import: simplify allocation in start_packfileJeff King, Feb 15, 2016
  26. 11/18 fetch-pack: simplify add_sought_entryJeff King, Feb 15, 2016
  27. 12/18 test-path-utils: fix normalize_path_copy output buffer sizeJeff King, Feb 15, 2016
  28. 13/18 sequencer: simplify memory allocation of get_messageJeff King, Feb 15, 2016
  29. Eric SunshineFeb 16, 2016
  30. 14/18 git-compat-util: drop mempcpy compat codeJeff King, Feb 15, 2016
  31. Eric SunshineFeb 16, 2016
  32. 15/18 transport_anonymize_url: use xstrfmtJeff King, Feb 15, 2016
  33. 16/18 diff_populate_gitlink: use a strbufJeff King, Feb 15, 2016
  34. 17/18 convert ewah/bitmap code to use xmallocJeff King, Feb 15, 2016
  35. 18/18 ewah: convert to REALLOC_ARRAY, etcJeff King, Feb 15, 2016
  36. Jeff KingFeb 15, 2016
  37. 0/21 hardening allocations against integer overflowJeff King, Feb 19, 2016
  38. 01/21 reflog_expire_cfg: NUL-terminate pattern fieldJeff King, Feb 19, 2016
  39. 02/21 add helpers for detecting size_t overflowJeff King, Feb 19, 2016
  40. 03/21 tree-diff: catch integer overflow in combine_diff_path allocationJeff King, Feb 19, 2016
  41. 04/21 harden REALLOC_ARRAY and xcalloc against size_t overflowJeff King, Feb 19, 2016
  42. René ScharfeFeb 20, 2016
  43. Jeff KingFeb 21, 2016
  44. 05/21 add helpers for allocating flex-array structsJeff King, Feb 19, 2016
  45. 06/21 convert manual allocations to argv_arrayJeff King, Feb 19, 2016
  46. Eric SunshineFeb 20, 2016
  47. Jeff KingFeb 20, 2016
  48. Eric SunshineFeb 20, 2016
  49. Jeff KingFeb 20, 2016
  50. Eric SunshineFeb 20, 2016
  51. Jeff KingFeb 20, 2016
  52. Eric SunshineFeb 20, 2016
  53. 07/21 convert trivial cases to ALLOC_ARRAYJeff King, Feb 19, 2016
  54. 08/21 use xmallocz to avoid size arithmeticJeff King, Feb 19, 2016
  55. 09/21 convert trivial cases to FLEX_ARRAY macrosJeff King, Feb 19, 2016
  56. 10/21 use st_add and st_mult for allocation size computationJeff King, Feb 19, 2016
  57. 11/21 prepare_{git,shell}_cmd: use argv_arrayJeff King, Feb 19, 2016
  58. 12/21 write_untracked_extension: use FLEX_ALLOC helperJeff King, Feb 19, 2016
  59. 13/21 fast-import: simplify allocation in start_packfileJeff King, Feb 19, 2016
  60. Junio C HamanoFeb 19, 2016
  61. Jeff KingFeb 19, 2016
  62. 14/21 fetch-pack: simplify add_sought_entryJeff King, Feb 19, 2016
  63. 15/21 test-path-utils: fix normalize_path_copy output buffer sizeJeff King, Feb 19, 2016
  64. 16/21 sequencer: simplify memory allocation of get_messageJeff King, Feb 19, 2016
  65. 17/21 git-compat-util: drop mempcpy compat codeJeff King, Feb 19, 2016
  66. 18/21 transport_anonymize_url: use xstrfmtJeff King, Feb 19, 2016
  67. 19/21 diff_populate_gitlink: use a strbufJeff King, Feb 19, 2016
  68. 20/21 convert ewah/bitmap code to use xmallocJeff King, Feb 19, 2016
  69. 21/21 ewah: convert to REALLOC_ARRAY, etcJeff King, Feb 19, 2016
  70. 0/22 hardening allocations against integer overflowJeff King, Feb 22, 2016
  71. 01/22 reflog_expire_cfg: NUL-terminate pattern fieldJeff King, Feb 22, 2016
  72. 02/22 add helpers for detecting size_t overflowJeff King, Feb 22, 2016
  73. 03/22 tree-diff: catch integer overflow in combine_diff_path allocationJeff King, Feb 22, 2016
  74. 04/22 harden REALLOC_ARRAY and xcalloc against size_t overflowJeff King, Feb 22, 2016
  75. 05/22 add helpers for allocating flex-array structsJeff King, Feb 22, 2016
  76. 06/22 argv-array: add detach functionJeff King, Feb 22, 2016
  77. 07/22 convert manual allocations to argv_arrayJeff King, Feb 22, 2016
  78. 08/22 convert trivial cases to ALLOC_ARRAYJeff King, Feb 22, 2016
  79. 09/22 use xmallocz to avoid size arithmeticJeff King, Feb 22, 2016
  80. 10/22 convert trivial cases to FLEX_ARRAY macrosJeff King, Feb 22, 2016
  81. 11/22 use st_add and st_mult for allocation size computationJeff King, Feb 22, 2016
  82. 12/22 prepare_{git,shell}_cmd: use argv_arrayJeff King, Feb 22, 2016
  83. 13/22 write_untracked_extension: use FLEX_ALLOC helperJeff King, Feb 22, 2016
  84. 14/22 fast-import: simplify allocation in start_packfileJeff King, Feb 22, 2016
  85. 15/22 fetch-pack: simplify add_sought_entryJeff King, Feb 22, 2016
  86. 16/22 test-path-utils: fix normalize_path_copy output buffer sizeJeff King, Feb 22, 2016
  87. 17/22 sequencer: simplify memory allocation of get_messageJeff King, Feb 22, 2016
  88. 18/22 git-compat-util: drop mempcpy compat codeJeff King, Feb 22, 2016
  89. 19/22 transport_anonymize_url: use xstrfmtJeff King, Feb 22, 2016
  90. 20/22 diff_populate_gitlink: use a strbufJeff King, Feb 22, 2016
  91. 21/22 convert ewah/bitmap code to use xmallocJeff King, Feb 22, 2016
  92. 22/22 ewah: convert to REALLOC_ARRAY, etcJeff King, Feb 22, 2016
  93. Junio C HamanoFeb 22, 2016

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.