git: refactor builtin handling to use a `struct strvec`
Similar as with the preceding commit, `handle_builtin()` does not properly track lifetimes of the `argv` array and its strings. As it may end up modifying the array this can lead to memory leaks in case it contains allocated strings. Refactor the function to use a `struct strvec` instead. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>maint
parent
ffc5c046fb
commit
1dd7c32daa
62
git.c
62
git.c
|
|
@ -696,63 +696,57 @@ void load_builtin_commands(const char *prefix, struct cmdnames *cmds)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef STRIP_EXTENSION
|
#ifdef STRIP_EXTENSION
|
||||||
static void strip_extension(const char **argv)
|
static void strip_extension(struct strvec *args)
|
||||||
{
|
{
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
if (strip_suffix(argv[0], STRIP_EXTENSION, &len))
|
if (strip_suffix(args->v[0], STRIP_EXTENSION, &len)) {
|
||||||
argv[0] = xmemdupz(argv[0], len);
|
char *stripped = xmemdupz(args->v[0], len);
|
||||||
|
strvec_replace(args, 0, stripped);
|
||||||
|
free(stripped);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
#define strip_extension(cmd)
|
#define strip_extension(cmd)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void handle_builtin(int argc, const char **argv)
|
static void handle_builtin(struct strvec *args)
|
||||||
{
|
{
|
||||||
struct strvec args = STRVEC_INIT;
|
|
||||||
const char **argv_copy = NULL;
|
|
||||||
const char *cmd;
|
const char *cmd;
|
||||||
struct cmd_struct *builtin;
|
struct cmd_struct *builtin;
|
||||||
|
|
||||||
strip_extension(argv);
|
strip_extension(args);
|
||||||
cmd = argv[0];
|
cmd = args->v[0];
|
||||||
|
|
||||||
/* Turn "git cmd --help" into "git help --exclude-guides cmd" */
|
/* Turn "git cmd --help" into "git help --exclude-guides cmd" */
|
||||||
if (argc > 1 && !strcmp(argv[1], "--help")) {
|
if (args->nr > 1 && !strcmp(args->v[1], "--help")) {
|
||||||
int i;
|
const char *exclude_guides_arg[] = { "--exclude-guides" };
|
||||||
|
|
||||||
argv[1] = argv[0];
|
strvec_replace(args, 1, args->v[0]);
|
||||||
argv[0] = cmd = "help";
|
strvec_replace(args, 0, "help");
|
||||||
|
cmd = "help";
|
||||||
for (i = 0; i < argc; i++) {
|
strvec_splice(args, 2, 0, exclude_guides_arg,
|
||||||
strvec_push(&args, argv[i]);
|
ARRAY_SIZE(exclude_guides_arg));
|
||||||
if (!i)
|
|
||||||
strvec_push(&args, "--exclude-guides");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
argc++;
|
builtin = get_builtin(cmd);
|
||||||
|
if (builtin) {
|
||||||
|
const char **argv_copy = NULL;
|
||||||
|
int ret;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* `run_builtin()` will modify the argv array, so we need to
|
* `run_builtin()` will modify the argv array, so we need to
|
||||||
* create a shallow copy such that we can free all of its
|
* create a shallow copy such that we can free all of its
|
||||||
* strings.
|
* strings.
|
||||||
*/
|
*/
|
||||||
CALLOC_ARRAY(argv_copy, argc + 1);
|
if (args->nr)
|
||||||
COPY_ARRAY(argv_copy, args.v, argc);
|
DUP_ARRAY(argv_copy, args->v, args->nr + 1);
|
||||||
|
|
||||||
argv = argv_copy;
|
ret = run_builtin(builtin, args->nr, argv_copy, the_repository);
|
||||||
}
|
strvec_clear(args);
|
||||||
|
|
||||||
builtin = get_builtin(cmd);
|
|
||||||
if (builtin) {
|
|
||||||
int ret = run_builtin(builtin, argc, argv, the_repository);
|
|
||||||
strvec_clear(&args);
|
|
||||||
free(argv_copy);
|
free(argv_copy);
|
||||||
exit(ret);
|
exit(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
strvec_clear(&args);
|
|
||||||
free(argv_copy);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execv_dashed_external(const char **argv)
|
static void execv_dashed_external(const char **argv)
|
||||||
|
|
@ -815,7 +809,7 @@ static int run_argv(struct strvec *args)
|
||||||
* process.
|
* process.
|
||||||
*/
|
*/
|
||||||
if (!done_alias)
|
if (!done_alias)
|
||||||
handle_builtin(args->nr, args->v);
|
handle_builtin(args);
|
||||||
else if (get_builtin(args->v[0])) {
|
else if (get_builtin(args->v[0])) {
|
||||||
struct child_process cmd = CHILD_PROCESS_INIT;
|
struct child_process cmd = CHILD_PROCESS_INIT;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -916,8 +910,10 @@ int cmd_main(int argc, const char **argv)
|
||||||
* that one cannot handle it.
|
* that one cannot handle it.
|
||||||
*/
|
*/
|
||||||
if (skip_prefix(cmd, "git-", &cmd)) {
|
if (skip_prefix(cmd, "git-", &cmd)) {
|
||||||
argv[0] = cmd;
|
strvec_push(&args, cmd);
|
||||||
handle_builtin(argc, argv);
|
strvec_pushv(&args, argv + 1);
|
||||||
|
handle_builtin(&args);
|
||||||
|
strvec_clear(&args);
|
||||||
die(_("cannot handle %s as a builtin"), cmd);
|
die(_("cannot handle %s as a builtin"), cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
test_description='test trace2 facility (perf target)'
|
test_description='test trace2 facility (perf target)'
|
||||||
|
|
||||||
TEST_PASSES_SANITIZE_LEAK=false
|
TEST_PASSES_SANITIZE_LEAK=true
|
||||||
. ./test-lib.sh
|
. ./test-lib.sh
|
||||||
|
|
||||||
# Turn off any inherited trace2 settings for this test.
|
# Turn off any inherited trace2 settings for this test.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue