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

Re: [PATCH 2/2] packfile: fix memory leak in add_delta_base_cache()

From
Junio C Hamano <gitster@pobox.com>
Date
Sep 28, 2020, 18:22 UTC
Message-ID
<xmqqlfgtn4lo.fsf@gitster.c.googlers.com>
In-Reply-To
<5b6e3019e08c6bccdee29018e99b0c6933fe05e0.1601311803.git.matheus.bernardino@usp.br>
Matheus Tavares <matheus.bernardino@usp.br> writes:
> When add_delta_base_cache() is called with a base that is already in the
> cache, no operation is performed. But the check is done after allocating
> space for a new entry, so we end up leaking memory on the early return.

Wow, that's so obvious a leak that it is surprising it has been unnoticed, especially given that the runtime inflation of the packfile was written so long time ago and was a central part of the system.

I had to dig and find out that the breakage was fairly recent from early this year, made in 31877c9a (object-store: allow threaded access to object reading, 2020-01-15).

Show 7 quoted lines
> Also, the caller always expect that the base will be inserted, so it
> never free()'s it. To fix both of these memory leaks, let's move the
> allocation of a new entry further down in add_delta_base_cache(), and
> make the function return an integer to indicate whether the insertion
> was performed or not. Then, make the caller free() the base when needed.
>
> Signed-off-by: Matheus Tavares <matheus.bernardino@usp.br>
Show 10 quoted lines
> @@ -1841,8 +1843,10 @@ void *unpack_entry(struct repository *r, struct packed_git *p, off_t obj_offset,
>  		 * thread could free() it (e.g. to make space for another entry)
>  		 * before we are done using it.
>  		 */
> -		if (!external_base)
> -			add_delta_base_cache(p, base_obj_offset, base, base_size, type);
> +		if (!external_base && !add_delta_base_cache(p, base_obj_offset,
> +						base, base_size, type)) {
> +			free(base);
> +		}

When you have to wrap a long expression, try to split after an operator near the root of the parse tree, e.g.

		if (!external_base &&
		    !add_delta_base_cache(p, base_obj_offset, base, base_size, type)) {
would make the result easier to follow.

I however suspect that it may be better let add_delta_base_cache() do the freeing. There is only one caller, and from its point of view, the timing when it throws the base at the cache (after the previous patch) is when it is done with it.

In other words we can think of the call to add_delta_base_cache() as the caller saying: "I am done with this, but somebody else might want to reuse it later, so do whatever you want to do with it".

If we were to go that route, it might even make sense to rename it to reflect that mentality from the viewpoint of the caller, but a single-caller helper like this one it may not matter all that much.

Thanks.
Previous: Matheus TavaresNext: Matheus Tavares
Message 8 of 12 in “RFC - concurrency causes segfault in git grep since 2.26.0”
  1. Phil HordSep 25, 2020
  2. Matheus TavaresSep 25, 2020
  3. Phil HordSep 25, 2020
  4. 0/2 Fix race condition and memory leak in delta base cacheMatheus Tavares, Sep 28, 2020
  5. 1/2 packfile: fix race condition on unpack_entry()Matheus Tavares, Sep 28, 2020
  6. Junio C HamanoSep 28, 2020
  7. 2/2 packfile: fix memory leak in add_delta_base_cache()Matheus Tavares, Sep 28, 2020
  8. Junio C HamanoSep 28, 2020
  9. 0/2 Fix race condition and memory leak in delta base cacheMatheus Tavares, Sep 29, 2020
  10. 1/2 packfile: fix race condition on unpack_entry()Matheus Tavares, Sep 29, 2020
  11. Phil HordOct 2, 2020
  12. 2/2 packfile: fix memory leak in add_delta_base_cache()Matheus Tavares, Sep 29, 2020

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.