Merge branch 'ps/leakfixes-part-10' into ps/bisect-double-free-fix

* ps/leakfixes-part-10: (27 commits)
  t: remove TEST_PASSES_SANITIZE_LEAK annotations
  test-lib: unconditionally enable leak checking
  t: remove unneeded !SANITIZE_LEAK prerequisites
  t: mark some tests as leak free
  t5601: work around leak sanitizer issue
  git-compat-util: drop now-unused `UNLEAK()` macro
  global: drop `UNLEAK()` annotation
  t/helper: fix leaking commit graph in "read-graph" subcommand
  builtin/branch: fix leaking sorting options
  builtin/init-db: fix leaking directory paths
  builtin/help: fix leaks in `check_git_cmd()`
  help: fix leaking return value from `help_unknown_cmd()`
  help: fix leaking `struct cmdnames`
  help: refactor to not use globals for reading config
  builtin/sparse-checkout: fix leaking sanitized patterns
  split-index: fix memory leak in `move_cache_to_base_index()`
  git: refactor builtin handling to use a `struct strvec`
  git: refactor alias handling to use a `struct strvec`
  strvec: introduce new `strvec_splice()` function
  line-log: fix leak when rewriting commit parents
  ...
This commit is contained in:
Junio C Hamano
2024-11-26 10:21:58 +09:00
950 changed files with 360 additions and 1248 deletions

View File

@ -1216,12 +1216,6 @@ parse_done:
output_option &= ~(OUTPUT_COLOR_LINE | OUTPUT_SHOW_AGE_WITH_COLOR);
output(&sb, output_option);
free((void *)sb.final_buf);
for (ent = sb.ent; ent; ) {
struct blame_entry *e = ent->next;
free(ent);
ent = e;
}
if (show_stats) {
printf("num read blob: %d\n", sb.num_read_blob);
@ -1230,6 +1224,12 @@ parse_done:
}
cleanup:
for (ent = sb.ent; ent; ) {
struct blame_entry *e = ent->next;
free(ent);
ent = e;
}
free(path);
cleanup_scoreboard(&sb);
release_revisions(&revs);

View File

@ -722,6 +722,7 @@ int cmd_branch(int argc,
static struct ref_sorting *sorting;
struct string_list sorting_options = STRING_LIST_INIT_DUP;
struct ref_format format = REF_FORMAT_INIT;
int ret;
struct option options[] = {
OPT_GROUP(N_("Generic options")),
@ -851,15 +852,15 @@ int cmd_branch(int argc,
if (list)
setup_auto_pager("branch", 1);
UNLEAK(sorting_options);
if (delete) {
if (!argc)
die(_("branch name required"));
return delete_branches(argc, argv, delete > 1, filter.kind, quiet);
ret = delete_branches(argc, argv, delete > 1, filter.kind, quiet);
goto out;
} else if (show_current) {
print_current_branch_name();
return 0;
ret = 0;
goto out;
} else if (list) {
/* git branch --list also shows HEAD when it is detached */
if ((filter.kind & FILTER_REFS_BRANCHES) && filter.detached)
@ -882,12 +883,13 @@ int cmd_branch(int argc,
ref_sorting_release(sorting);
ref_filter_clear(&filter);
ref_format_clear(&format);
return 0;
ret = 0;
goto out;
} else if (edit_description) {
const char *branch_name;
struct strbuf branch_ref = STRBUF_INIT;
struct strbuf buf = STRBUF_INIT;
int ret = 1; /* assume failure */
if (!argc) {
if (filter.detached)
@ -901,18 +903,22 @@ int cmd_branch(int argc,
}
strbuf_addf(&branch_ref, "refs/heads/%s", branch_name);
if (!refs_ref_exists(get_main_ref_store(the_repository), branch_ref.buf))
if (!refs_ref_exists(get_main_ref_store(the_repository), branch_ref.buf)) {
error((!argc || branch_checked_out(branch_ref.buf))
? _("no commit on branch '%s' yet")
: _("no branch named '%s'"),
branch_name);
else if (!edit_branch_description(branch_name))
ret = 1;
} else if (!edit_branch_description(branch_name)) {
ret = 0; /* happy */
} else {
ret = 1;
}
strbuf_release(&branch_ref);
strbuf_release(&buf);
return ret;
goto out;
} else if (copy || rename) {
if (!argc)
die(_("branch name required"));
@ -1000,12 +1006,17 @@ int cmd_branch(int argc,
create_branches_recursively(the_repository, branch_name,
start_name, NULL, force,
reflog, quiet, track, 0);
return 0;
ret = 0;
goto out;
}
create_branch(the_repository, branch_name, start_name, force, 0,
reflog, quiet, track, 0);
} else
usage_with_options(builtin_branch_usage, options);
return 0;
ret = 0;
out:
string_list_clear(&sorting_options, 0);
return ret;
}

View File

@ -1586,7 +1586,6 @@ int cmd_clone(int argc,
free(dir);
free(path);
free(repo_to_free);
UNLEAK(repo);
junk_mode = JUNK_LEAVE_ALL;
transport_ls_refs_options_release(&transport_ls_refs_options);

View File

@ -628,6 +628,5 @@ int cmd_diff(int argc,
release_revisions(&rev);
object_array_clear(&ent);
symdiff_release(&sdiff);
UNLEAK(blob);
return result;
}

View File

@ -551,12 +551,12 @@ static void show_html_page(const char *page)
open_html(page_path.buf);
}
static const char *check_git_cmd(const char* cmd)
static char *check_git_cmd(const char *cmd)
{
char *alias;
if (is_git_command(cmd))
return cmd;
return xstrdup(cmd);
alias = alias_lookup(cmd);
if (alias) {
@ -589,14 +589,13 @@ static const char *check_git_cmd(const char* cmd)
die(_("bad alias.%s string: %s"), cmd,
split_cmdline_strerror(count));
free(argv);
UNLEAK(alias);
return alias;
}
if (exclude_guides)
return help_unknown_cmd(cmd);
return cmd;
return xstrdup(cmd);
}
static void no_help_format(const char *opt_mode, enum help_format fmt)
@ -642,6 +641,7 @@ int cmd_help(int argc,
{
int nongit;
enum help_format parsed_help_format;
char *command = NULL;
const char *page;
argc = parse_options(argc, argv, prefix, builtin_help_options,
@ -713,9 +713,9 @@ int cmd_help(int argc,
if (help_format == HELP_FORMAT_NONE)
help_format = parse_help_format(DEFAULT_HELP_FORMAT);
argv[0] = check_git_cmd(argv[0]);
command = check_git_cmd(argv[0]);
page = cmd_to_page(argv[0]);
page = cmd_to_page(command);
switch (help_format) {
case HELP_FORMAT_NONE:
case HELP_FORMAT_MAN:
@ -729,5 +729,6 @@ int cmd_help(int argc,
break;
}
free(command);
return 0;
}

View File

@ -75,10 +75,12 @@ int cmd_init_db(int argc,
const char *prefix,
struct repository *repo UNUSED)
{
const char *git_dir;
char *git_dir;
const char *real_git_dir = NULL;
const char *work_tree;
char *real_git_dir_to_free = NULL;
char *work_tree = NULL;
const char *template_dir = NULL;
char *template_dir_to_free = NULL;
unsigned int flags = 0;
const char *object_format = NULL;
const char *ref_format = NULL;
@ -106,6 +108,7 @@ int cmd_init_db(int argc,
N_("specify the reference format to use")),
OPT_END()
};
int ret;
argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0);
@ -113,12 +116,10 @@ int cmd_init_db(int argc,
die(_("options '%s' and '%s' cannot be used together"), "--separate-git-dir", "--bare");
if (real_git_dir && !is_absolute_path(real_git_dir))
real_git_dir = real_pathdup(real_git_dir, 1);
real_git_dir = real_git_dir_to_free = real_pathdup(real_git_dir, 1);
if (template_dir && *template_dir && !is_absolute_path(template_dir)) {
template_dir = absolute_pathdup(template_dir);
UNLEAK(template_dir);
}
if (template_dir && *template_dir && !is_absolute_path(template_dir))
template_dir = template_dir_to_free = absolute_pathdup(template_dir);
if (argc == 1) {
int mkdir_tried = 0;
@ -192,7 +193,7 @@ int cmd_init_db(int argc,
* Set up the default .git directory contents
*/
if (!git_dir)
git_dir = DEFAULT_GIT_DIR_ENVIRONMENT;
git_dir = xstrdup(DEFAULT_GIT_DIR_ENVIRONMENT);
/*
* When --separate-git-dir is used inside a linked worktree, take
@ -213,6 +214,7 @@ int cmd_init_db(int argc,
if (chdir(mainwt.buf) < 0)
die_errno(_("cannot chdir to %s"), mainwt.buf);
strbuf_release(&mainwt);
free(git_dir);
git_dir = strbuf_detach(&sb, NULL);
}
strbuf_release(&sb);
@ -245,12 +247,14 @@ int cmd_init_db(int argc,
set_git_work_tree(work_tree);
}
UNLEAK(real_git_dir);
UNLEAK(git_dir);
UNLEAK(work_tree);
flags |= INIT_DB_EXIST_OK;
return init_db(git_dir, real_git_dir, template_dir, hash_algo,
ref_storage_format, initial_branch,
init_shared_repository, flags);
ret = init_db(git_dir, real_git_dir, template_dir, hash_algo,
ref_storage_format, initial_branch,
init_shared_repository, flags);
free(template_dir_to_free);
free(real_git_dir_to_free);
free(work_tree);
free(git_dir);
return ret;
}

View File

@ -669,7 +669,7 @@ static void add_patterns_literal(int argc, const char **argv,
add_patterns_from_input(pl, argc, argv, use_stdin ? stdin : NULL);
}
static int modify_pattern_list(int argc, const char **argv, int use_stdin,
static int modify_pattern_list(struct strvec *args, int use_stdin,
enum modify_type m)
{
int result;
@ -679,13 +679,13 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
switch (m) {
case ADD:
if (core_sparse_checkout_cone)
add_patterns_cone_mode(argc, argv, pl, use_stdin);
add_patterns_cone_mode(args->nr, args->v, pl, use_stdin);
else
add_patterns_literal(argc, argv, pl, use_stdin);
add_patterns_literal(args->nr, args->v, pl, use_stdin);
break;
case REPLACE:
add_patterns_from_input(pl, argc, argv,
add_patterns_from_input(pl, args->nr, args->v,
use_stdin ? stdin : NULL);
break;
}
@ -706,12 +706,12 @@ static int modify_pattern_list(int argc, const char **argv, int use_stdin,
return result;
}
static void sanitize_paths(int argc, const char **argv,
static void sanitize_paths(struct strvec *args,
const char *prefix, int skip_checks)
{
int i;
if (!argc)
if (!args->nr)
return;
if (prefix && *prefix && core_sparse_checkout_cone) {
@ -721,8 +721,11 @@ static void sanitize_paths(int argc, const char **argv,
*/
int prefix_len = strlen(prefix);
for (i = 0; i < argc; i++)
argv[i] = prefix_path(prefix, prefix_len, argv[i]);
for (i = 0; i < args->nr; i++) {
char *prefixed_path = prefix_path(prefix, prefix_len, args->v[i]);
strvec_replace(args, i, prefixed_path);
free(prefixed_path);
}
}
if (skip_checks)
@ -732,20 +735,20 @@ static void sanitize_paths(int argc, const char **argv,
die(_("please run from the toplevel directory in non-cone mode"));
if (core_sparse_checkout_cone) {
for (i = 0; i < argc; i++) {
if (argv[i][0] == '/')
for (i = 0; i < args->nr; i++) {
if (args->v[i][0] == '/')
die(_("specify directories rather than patterns (no leading slash)"));
if (argv[i][0] == '!')
if (args->v[i][0] == '!')
die(_("specify directories rather than patterns. If your directory starts with a '!', pass --skip-checks"));
if (strpbrk(argv[i], "*?[]"))
if (strpbrk(args->v[i], "*?[]"))
die(_("specify directories rather than patterns. If your directory really has any of '*?[]\\' in it, pass --skip-checks"));
}
}
for (i = 0; i < argc; i++) {
for (i = 0; i < args->nr; i++) {
struct cache_entry *ce;
struct index_state *index = the_repository->index;
int pos = index_name_pos(index, argv[i], strlen(argv[i]));
int pos = index_name_pos(index, args->v[i], strlen(args->v[i]));
if (pos < 0)
continue;
@ -754,9 +757,9 @@ static void sanitize_paths(int argc, const char **argv,
continue;
if (core_sparse_checkout_cone)
die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), argv[i]);
die(_("'%s' is not a directory; to treat it as a directory anyway, rerun with --skip-checks"), args->v[i]);
else
warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), argv[i]);
warning(_("pass a leading slash before paths such as '%s' if you want a single file (see NON-CONE PROBLEMS in the git-sparse-checkout manual)."), args->v[i]);
}
}
@ -780,6 +783,8 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
N_("read patterns from standard in")),
OPT_END(),
};
struct strvec patterns = STRVEC_INIT;
int ret;
setup_work_tree();
if (!core_apply_sparse_checkout)
@ -791,9 +796,14 @@ static int sparse_checkout_add(int argc, const char **argv, const char *prefix)
builtin_sparse_checkout_add_options,
builtin_sparse_checkout_add_usage, 0);
sanitize_paths(argc, argv, prefix, add_opts.skip_checks);
for (int i = 0; i < argc; i++)
strvec_push(&patterns, argv[i]);
sanitize_paths(&patterns, prefix, add_opts.skip_checks);
return modify_pattern_list(argc, argv, add_opts.use_stdin, ADD);
ret = modify_pattern_list(&patterns, add_opts.use_stdin, ADD);
strvec_clear(&patterns);
return ret;
}
static char const * const builtin_sparse_checkout_set_usage[] = {
@ -826,6 +836,8 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
PARSE_OPT_NONEG),
OPT_END(),
};
struct strvec patterns = STRVEC_INIT;
int ret;
setup_work_tree();
repo_read_index(the_repository);
@ -846,13 +858,18 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
* top-level directory (much as 'init' would do).
*/
if (!core_sparse_checkout_cone && !set_opts.use_stdin && argc == 0) {
argv = default_patterns;
argc = default_patterns_nr;
for (int i = 0; i < default_patterns_nr; i++)
strvec_push(&patterns, default_patterns[i]);
} else {
sanitize_paths(argc, argv, prefix, set_opts.skip_checks);
for (int i = 0; i < argc; i++)
strvec_push(&patterns, argv[i]);
sanitize_paths(&patterns, prefix, set_opts.skip_checks);
}
return modify_pattern_list(argc, argv, set_opts.use_stdin, REPLACE);
ret = modify_pattern_list(&patterns, set_opts.use_stdin, REPLACE);
strvec_clear(&patterns);
return ret;
}
static char const * const builtin_sparse_checkout_reapply_usage[] = {