Re: [PATCH 03/11] submodule--helper: fix "module_clone_data" memory leaks

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> writes:

> The "path" member can come from "argv" (i.e. not malloc'd), or it can
> be something we determine at runtime. In the latter case let's save
> away a pointer to free() to avoid leaking memory.

[...]

> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index 73717be957c..23ab9c7e349 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -1511,6 +1511,7 @@ static int module_deinit(int argc, const char **argv, const char *prefix)
>  struct module_clone_data {
>  	const char *prefix;
>  	const char *path;
> +	char *path_free;
>  	const char *name;
>  	const char *url;
>  	const char *depth;
> @@ -1527,6 +1528,11 @@ struct module_clone_data {
>  	.single_branch = -1, \
>  }
>  
> +static void module_clone_data_release(struct module_clone_data *cd)
> +{
> +	free(cd->path_free);
> +}
> +
>  struct submodule_alternate_setup {
>  	const char *submodule_name;
>  	enum SUBMODULE_ALTERNATE_ERROR_MODE {
> @@ -1651,9 +1657,9 @@ static int clone_submodule(struct module_clone_data *clone_data)
>  
>  	if (!is_absolute_path(clone_data->path)) {
>  		strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
> -		clone_data->path = strbuf_detach(&sb, NULL);
> +		clone_data->path = clone_data->path_free = strbuf_detach(&sb, NULL);
>  	} else {
> -		clone_data->path = xstrdup(clone_data->path);
> +		clone_data->path = clone_data->path_free = xstrdup(clone_data->path);
>  	}

Hm, having .path_free doesn't seem necessary. If I'm reading the code
correctly,

- in module_clone() we set clone_data.path from argv
- then we unconditionally call clone_submodule(), which does all of the
  hard work
- in clone_submodule(), we always hit this conditional, which means that
  past this point, clone_data.path is always free()-able.

which suggests that we don't need clone_data.path_free at all. I suspect
that just this

   static void module_clone_data_release(struct module_clone_data *cd)
   {
   	free(cd->path);
   }

is enough to plug the leak (though admittedly, I haven't properly tested
the leak because it's been a PITA to set up locally).

That's a pretty hacky suggestion though, since we're still using the
same member to hold free()-able and non-free()-able memory. Instead,
maybe we could move this "clone_data.path = freeable" logic into
module_clone(), like:

  diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
  index 73717be957..d67d4b9647 100644
  --- a/builtin/submodule--helper.c
  +++ b/builtin/submodule--helper.c
  @@ -1649,13 +1649,6 @@ static int clone_submodule(struct module_clone_data *clone_data)
    sm_gitdir = absolute_pathdup(sb.buf);
    strbuf_reset(&sb);

  -	if (!is_absolute_path(clone_data->path)) {
  -		strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_data->path);
  -		clone_data->path = strbuf_detach(&sb, NULL);
  -	} else {
  -		clone_data->path = xstrdup(clone_data->path);
  -	}
  -
    if (validate_submodule_git_dir(sm_gitdir, clone_data->name) < 0)
      die(_("refusing to create/use '%s' in another submodule's "
            "git dir"), sm_gitdir);
  @@ -1745,12 +1738,13 @@ static int module_clone(int argc, const char **argv, const char *prefix)
    int dissociate = 0, quiet = 0, progress = 0, require_init = 0;
    struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT;
    struct list_objects_filter_options filter_options = { 0 };
  +	const char *clone_path;

    struct option module_clone_options[] = {
      OPT_STRING(0, "prefix", &clone_data.prefix,
          N_("path"),
          N_("alternative anchor for relative paths")),
  -		OPT_STRING(0, "path", &clone_data.path,
  +		OPT_STRING(0, "path", &clone_path,
          N_("path"),
          N_("where the new submodule will be cloned to")),
      OPT_STRING(0, "name", &clone_data.name,
  @@ -1795,6 +1789,15 @@ static int module_clone(int argc, const char **argv, const char *prefix)
    clone_data.require_init = !!require_init;
    clone_data.filter_options = &filter_options;

  +	if (!is_absolute_path(clone_path)) {
  +		struct strbuf sb = STRBUF_INIT;
  +		strbuf_addf(&sb, "%s/%s", get_git_work_tree(), clone_path);
  +		clone_data.path = strbuf_detach(&sb, NULL);
  +		strbuf_release(&sb);
  +	} else {
  +		clone_data.path = xstrdup(clone_path);
  +	}
  +
    if (argc || !clone_data.url || !clone_data.path || !*(clone_data.path))
      usage_with_options(git_submodule_helper_usage,
            module_clone_options);




[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux