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

[PATCH v2 13/13] sparse-checkout: free duplicate hashmap entries

From
Jeff King <peff@peff.net>
Date
Jun 4, 2024, 10:13 UTC
Message-ID
<20240604101340.GM1304593@coredump.intra.peff.net>
In-Reply-To
<20240604100814.GA1304520@coredump.intra.peff.net>

In insert_recursive_pattern(), we create a new pattern_entry to insert into the parent_hashmap. If we find that the same entry already exists in the hashmap, we skip adding the new one. But we forget to free the new one, creating a leak.

We can fix it by cleaning up the discarded entry. It would probably be possible to avoid creating it in the first place, but it's non-trivial. We'd have to define a "keydata" struct that lets us compare the existing entries to the broken-out fields. It's probably not worth the complexity, so we'll punt on that for now.

There is one subtlety here: our insertion is happening in a loop, with each iteration looking at the pattern we just inserted (hence the "recursive" in the name). So if we skip insertion, what do we look at?

The obvious answer is that we should remember the existing duplicate we found and use that. But I _think_ in that case, we probably already have all of the recursive bits already (from when the original entry was added). And so just breaking out of the loop would be correct. But I'm not 100% sure on that; after all, the original leaky code could have done the same break, but it didn't.

So I went with the "obvious answer" above, which has no chance of changing the behavior aside from fixing the leak.

With this patch, t1091 can now be marked leak-free.
Signed-off-by: Jeff King <peff@peff.net>
---
 builtin/sparse-checkout.c          | 9 ++++++++-
 t/t1091-sparse-checkout-builtin.sh | 1 +
 2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/builtin/sparse-checkout.c b/builtin/sparse-checkout.c
index e648e035ab..3f2bfce8fa 100644
--- a/builtin/sparse-checkout.c
+++ b/builtin/sparse-checkout.c
@@ -523,6 +523,7 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
 		char *slash = strrchr(e->pattern, '/');
 		char *oldpattern = e->pattern;
 		size_t newlen;
+		struct pattern_entry *dup;
 
 		if (!slash || slash == e->pattern)
 			break;
@@ -533,8 +534,14 @@ static void insert_recursive_pattern(struct pattern_list *pl, struct strbuf *pat
 		e->pattern = xstrndup(oldpattern, newlen);
 		hashmap_entry_init(&e->ent, fspathhash(e->pattern));
 
-		if (!hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL))
+		dup = hashmap_get_entry(&pl->parent_hashmap, e, ent, NULL);
+		if (!dup) {
 			hashmap_add(&pl->parent_hashmap, &e->ent);
+		} else {
+			free(e->pattern);
+			free(e);
+			e = dup;
+		}
 	}
 }
 
diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
index ab3a105fff..8c5cd651b4 100755
--- a/t/t1091-sparse-checkout-builtin.sh
+++ b/t/t1091-sparse-checkout-builtin.sh
@@ -8,6 +8,7 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 GIT_TEST_SPLIT_INDEX=false
 export GIT_TEST_SPLIT_INDEX
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 list_files() {
-- 
2.45.2.807.g3b5fadc4da
Previous: Jeff KingNext: Patrick Steinhardt
Message 42 of 43 in “leak fixes for sparse-checkout code”
  1. 0/13 leak fixes for sparse-checkout codeJeff King, May 31, 2024
  2. 01/13 sparse-checkout: free string list in write_cone_to_file()Jeff King, May 31, 2024
  3. 02/13 sparse-checkout: pass string literals directly to add_pattern()Jeff King, May 31, 2024
  4. Junio C HamanoMay 31, 2024
  5. Jeff KingJun 4, 2024
  6. 03/13 dir.c: free strings in sparse cone pattern hashmapsJeff King, May 31, 2024
  7. 04/13 sparse-checkout: clear patterns when init() sees existing sparse fileJeff King, May 31, 2024
  8. 05/13 dir.c: free removed sparse-pattern hashmap entriesJeff King, May 31, 2024
  9. 06/13 dir.c: always copy input to add_pattern()Jeff King, May 31, 2024
  10. Junio C HamanoMay 31, 2024
  11. 07/13 sparse-checkout: reuse --stdin buffer when reading patternsJeff King, May 31, 2024
  12. 08/13 sparse-checkout: always free "line" strbuf after reading inputJeff King, May 31, 2024
  13. 09/13 sparse-checkout: refactor temporary sparse_checkout_patternsJeff King, May 31, 2024
  14. Patrick SteinhardtJun 4, 2024
  15. Jeff KingJun 4, 2024
  16. 10/13 sparse-checkout: free sparse_filename after useJeff King, May 31, 2024
  17. Patrick SteinhardtJun 4, 2024
  18. Jeff KingJun 4, 2024
  19. Patrick SteinhardtJun 4, 2024
  20. 11/13 sparse-checkout: free pattern list in sparse_checkout_list()Jeff King, May 31, 2024
  21. 12/13 sparse-checkout: free string list after displayingJeff King, May 31, 2024
  22. 13/13 sparse-checkout: free duplicate hashmap entriesJeff King, May 31, 2024
  23. Patrick SteinhardtJun 4, 2024
  24. Jeff KingMay 31, 2024
  25. Junio C HamanoMay 31, 2024
  26. 0/13 leak fixes for sparse-checkout codeJeff King, Jun 4, 2024
  27. 01/13 sparse-checkout: free string list in write_cone_to_file()Jeff King, Jun 4, 2024
  28. 02/13 sparse-checkout: pass string literals directly to add_pattern()Jeff King, Jun 4, 2024
  29. 03/13 dir.c: free strings in sparse cone pattern hashmapsJeff King, Jun 4, 2024
  30. 04/13 sparse-checkout: clear patterns when init() sees existing sparse fileJeff King, Jun 4, 2024
  31. 05/13 dir.c: free removed sparse-pattern hashmap entriesJeff King, Jun 4, 2024
  32. 06/13 dir.c: always copy input to add_pattern()Jeff King, Jun 4, 2024
  33. René ScharfeJun 5, 2024
  34. Jeff KingJun 5, 2024
  35. Junio C HamanoJun 5, 2024
  36. 07/13 sparse-checkout: reuse --stdin buffer when reading patternsJeff King, Jun 4, 2024
  37. 08/13 sparse-checkout: always free "line" strbuf after reading inputJeff King, Jun 4, 2024
  38. 09/13 sparse-checkout: refactor temporary sparse_checkout_patternsJeff King, Jun 4, 2024
  39. 10/13 sparse-checkout: free sparse_filename after useJeff King, Jun 4, 2024
  40. 11/13 sparse-checkout: free pattern list in sparse_checkout_list()Jeff King, Jun 4, 2024
  41. 12/13 sparse-checkout: free string list after displayingJeff King, Jun 4, 2024
  42. 13/13 sparse-checkout: free duplicate hashmap entriesJeff King, Jun 4, 2024
  43. Patrick SteinhardtJun 4, 2024

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.