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

Re: [PATCH 2/2] sequencer.c: plug mem leak in git_sequencer_config

From
Jeff King <peff@peff.net>
Date
Jun 4, 2018, 03:56 UTC
Message-ID
<20180604035637.GA15408@sigill.intra.peff.net>
In-Reply-To
<xmqqmuwb5i7k.fsf@gitster-ct.c.googlers.com>
On Mon, Jun 04, 2018 at 12:44:15PM +0900, Junio C Hamano wrote:
Show 22 quoted lines
> >> diff --git a/sequencer.c b/sequencer.c
> >> index b98690ecd41..aba03e9429a 100644
> >> --- a/sequencer.c
> >> +++ b/sequencer.c
> >> @@ -175,6 +175,7 @@ static int git_sequencer_config(const char *k, const char *v, void *cb)
> >>  			warning(_("invalid commit message cleanup mode '%s'"),
> >>  				  s);
> >>  
> >> +		free(s);
> >>  		return status;
> >>  	}
> >
> > Shouldn't 's' now lose 'const'?  After all, git_config_string()
> > gives you an allocated memory so...
> 
> Yikes.  Should git_config_string() and git_config_pathname() take
> "char **dst" instead of "const char **" as their out-location
> parameter?  They both assign a pointer to an allocated piece of
> memory for the caller to own or dispose of, but because of
> const-ness of the pointee their first parameter has, a caller like
> this one must declare "const char *s" yet is forced to call free()
> not to leak the value when it is done.

I've looked into it before, but that causes its own wave of headaches. The source of the problem is that we do:

  const char *some_var = "default";
  ...
  git_config_string(&some_var, ...);

So sometimes some_var needs to be freed and sometimes not (and every one of those uses is a potential leak, but it's OK because they're all program-lifetime globals anyway, and people don't _tend_ to set the same option over and over, leaking heap memory). And C being C, we can't convert a pointer-to-pointer-to-const into a pointer-to-pointer without an explicit cast.

Doing it "right" in C would probably involve two variables:
  const char *some_var = "default";
  const char *some_var_storage = NULL;
  int git_config_string_smart(const char **ptr, char **storage,
                              const char *var, const char *value)
  {
        ...
	free(*storage);
	*ptr = *storage = xstrdup(value);
	return 0;
  }
  #define GIT_CONFIG_STRING(name, var, value) \
  git_config_string_smart(&(name), &(name##_storage), var, value)
Or something like that.

We could also get away from an out-parameter and use the return type, since the single-pointer conversion is OK. But the primary value of git_config_string() is that it lets you return the error code as a one-liner.

-Peff
Previous: Junio C HamanoNext: Junio C Hamano
Message 5 of 11 in “sequencer.c: plug leaks in do_pick_commit”
  1. 1/2 sequencer.c: plug leaks in do_pick_commitStefan Beller, Jun 1, 2018
  2. 2/2 sequencer.c: plug mem leak in git_sequencer_configStefan Beller, Jun 1, 2018
  3. Junio C HamanoJun 4, 2018
  4. Junio C HamanoJun 4, 2018
  5. Jeff KingJun 4, 2018
  6. Junio C HamanoJun 4, 2018
  7. Jeff KingJun 4, 2018
  8. Junio C HamanoJun 4, 2018
  9. Johannes SchindelinJun 21, 2018
  10. Jeff KingJun 21, 2018
  11. Jeff KingJun 4, 2018

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.