Skip to contentSkip to conversation

fsmonitor: fix khash memory leak in do_handle_client

PATCH Superseded Paul Tarjan via GitGitGadget 4 participants 6 messages Dec 30, 2025 – Jan 4

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 fsmonitor: fix khash memory leak in do_handle_client

From: Paul Tarjan <[email protected]>

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. Two issues existed:

1. kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself (allocated by kh_init_str via xcalloc). This caused a 40-byte leak per request.

2. The khash was freed mid-function rather than in the cleanup section, so if the worker thread was interrupted before reaching that point during daemon shutdown, the memory would leak.

Fix both issues by:
- Initializing shown = NULL at declaration
- Using kh_destroy_str() which handles NULL and frees both internal arrays and the struct itself
- Moving the cleanup to the cleanup section so it runs on all exit paths

---
fsmonitor: fix khash memory leak in do_handle_client

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. Two issues existed:

1. kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself (allocated by kh_init_str via xcalloc). This caused a 40-byte leak per request.

2. The khash was freed mid-function rather than in the cleanup section, so if the worker thread was interrupted before reaching that point during daemon shutdown, the memory would leak.

Fix both issues by:

* Initializing shown = NULL at declaration
* Using kh_destroy_str() which handles NULL and frees both internal arrays and the struct itself
* Moving the cleanup to the cleanup section so it runs on all exit paths

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2148%2Fptarjan%2Fclaude%2Ffix-fsmonitor-hashmap-leak-gfDCU-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2148/ptarjan/claude/fix-fsmonitor-hashmap-leak-gfDCU-v1
Pull-Request: https://github.com/git/git/pull/2148

 builtin/fsmonitor--daemon.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
builtin/fsmonitor--daemon.c +2 -3
index 242c594646..bc4571938c 100644
@@ -671,7 +671,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	const struct fsmonitor_batch *batch;
 	struct fsmonitor_batch *remainder = NULL;
 	intmax_t count = 0, duplicates = 0;
-	kh_str_t *shown;
+	kh_str_t *shown = NULL;
 	int hash_ret;
 	int do_trivial = 0;
 	int do_flush = 0;
@@ -909,8 +909,6 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 		total_response_len += payload.len;
 	}
 
-	kh_release_str(shown);
-
 	pthread_mutex_lock(&state->main_lock);
 
 	if (token_data->client_ref_count > 0)
@@ -954,6 +952,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates);
 
 cleanup:
+	kh_destroy_str(shown);
 	strbuf_release(&response_token);
 	strbuf_release(&requested_token_id);
 	strbuf_release(&payload);

base-commit: 7c7698a654a7a0031f65b0ab0c1c4e438e95df60

Signature · 1 line
gitgitgadget
#1 lore raw
Quoted 24 lines · Paul Tarjan via GitGitGadget

From: Paul Tarjan <[email protected]>

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. Two issues existed:

1. kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself (allocated by kh_init_str via xcalloc). This caused a 40-byte leak per request.

2. The khash was freed mid-function rather than in the cleanup section, so if the worker thread was interrupted before reaching that point during daemon shutdown, the memory would leak.

Fix both issues by:
- Initializing shown = NULL at declaration
- Using kh_destroy_str() which handles NULL and frees both internal arrays and the struct itself
- Moving the cleanup to the cleanup section so it runs on all exit paths

---
fsmonitor: fix khash memory leak in do_handle_client

Quoted 7 lines

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. Two issues existed:

1. kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself (allocated by kh_init_str via xcalloc). This caused a 40-byte leak per request.

Makes sense.

Quoted 4 lines

2. The khash was freed mid-function rather than in the cleanup section, so if the worker thread was interrupted before reaching that point during daemon shutdown, the memory would leak.

Really? Would an interrupted thread even reach its cleanup section?

Quoted 48 lines

Fix both issues by:

* Initializing shown = NULL at declaration
* Using kh_destroy_str() which handles NULL and frees both internal arrays and the struct itself
* Moving the cleanup to the cleanup section so it runs on all exit paths

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2148%2Fptarjan%2Fclaude%2Ffix-fsmonitor-hashmap-leak-gfDCU-v1
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2148/ptarjan/claude/fix-fsmonitor-hashmap-leak-gfDCU-v1
Pull-Request: https://github.com/git/git/pull/2148

 builtin/fsmonitor--daemon.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
builtin/fsmonitor--daemon.c +2 -3
index 242c594646..bc4571938c 100644
@@ -671,7 +671,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	const struct fsmonitor_batch *batch;
 	struct fsmonitor_batch *remainder = NULL;
 	intmax_t count = 0, duplicates = 0;
-	kh_str_t *shown;
+	kh_str_t *shown = NULL;
 	int hash_ret;
 	int do_trivial = 0;
 	int do_flush = 0;
@@ -909,8 +909,6 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 		total_response_len += payload.len;
 	}
 
-	kh_release_str(shown);
-
 	pthread_mutex_lock(&state->main_lock);
 
 	if (token_data->client_ref_count > 0)
@@ -954,6 +952,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates);
 
 cleanup:
+	kh_destroy_str(shown);
 	strbuf_release(&response_token);
 	strbuf_release(&requested_token_id);
 	strbuf_release(&payload);

base-commit: 7c7698a654a7a0031f65b0ab0c1c4e438e95df60

#2 lore raw

PATCH v2 1/1 fsmonitor: fix khash memory leak in do_handle_client

In reply to Paul Tarjan via GitGitGadget

From: Paul Tarjan <[email protected]>

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. However, kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself, which is allocated by kh_init_str() via xcalloc. This caused a 40-byte leak per client request.

Fix by using kh_destroy_str() which properly frees both internal arrays and the struct itself. Also move the cleanup to the cleanup section and initialize shown to NULL so that kh_destroy_str() is safe to call on all exit paths.

---
fsmonitor: fix khash memory leak in do_handle_client

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. However, kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself, which is allocated by kh_init_str() via xcalloc. This caused a 40-byte leak per client request.

Fix by using kh_destroy_str() which properly frees both internal arrays and the struct itself. Also move the cleanup to the cleanup section and initialize shown to NULL so that kh_destroy_str() is safe to call on all exit paths.

Changes since v1:

* Removed incorrect claim about interrupted threads reaching cleanup
* Simplified commit message to focus on the real bug (kh_release vs kh_destroy)

Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-2148%2Fptarjan%2Fclaude%2Ffix-fsmonitor-hashmap-leak-gfDCU-v2
Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-2148/ptarjan/claude/fix-fsmonitor-hashmap-leak-gfDCU-v2
Pull-Request: https://github.com/git/git/pull/2148

Range-diff vs v1:

1: 18670d3230 ! 1: 0a754c7f09 fsmonitor: fix khash memory leak in do_handle_client
@@ Commit message
fsmonitor: fix khash memory leak in do_handle_client

The do_handle_client() function allocates a khash table to de-duplicate
- pathnames when responding to client requests. Two issues existed:
+ pathnames when responding to client requests. However, kh_release_str()
+ was used instead of kh_destroy_str(). The release function only frees
+ internal arrays (flags, keys, vals) but not the struct itself, which is
+ allocated by kh_init_str() via xcalloc. This caused a 40-byte leak per
+ client request.

- 1. kh_release_str() was used instead of kh_destroy_str(). The release
- function only frees internal arrays (flags, keys, vals) but not the
- struct itself (allocated by kh_init_str via xcalloc). This caused a
- 40-byte leak per request.
+ Fix by using kh_destroy_str() which properly frees both internal arrays
+ and the struct itself. Also move the cleanup to the cleanup section and
+ initialize shown to NULL so that kh_destroy_str() is safe to call on all
+ exit paths.

- 2. The khash was freed mid-function rather than in the cleanup section,
- so if the worker thread was interrupted before reaching that point
- during daemon shutdown, the memory would leak.
-
- Fix both issues by:
- - Initializing shown = NULL at declaration
- - Using kh_destroy_str() which handles NULL and frees both internal
- arrays and the struct itself
- - Moving the cleanup to the cleanup section so it runs on all exit paths
-
- Signed-off-by: Claude <[email protected]>
+ Signed-off-by: Paul Tarjan <[email protected]>

## builtin/fsmonitor--daemon.c ##
@@ builtin/fsmonitor--daemon.c: static int do_handle_client(struct fsmonitor_daemon_state *state,

 builtin/fsmonitor--daemon.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)
builtin/fsmonitor--daemon.c +2 -3
index 242c594646..bc4571938c 100644
@@ -671,7 +671,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	const struct fsmonitor_batch *batch;
 	struct fsmonitor_batch *remainder = NULL;
 	intmax_t count = 0, duplicates = 0;
-	kh_str_t *shown;
+	kh_str_t *shown = NULL;
 	int hash_ret;
 	int do_trivial = 0;
 	int do_flush = 0;
@@ -909,8 +909,6 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 		total_response_len += payload.len;
 	}
 
-	kh_release_str(shown);
-
 	pthread_mutex_lock(&state->main_lock);
 
 	if (token_data->client_ref_count > 0)
@@ -954,6 +952,7 @@ static int do_handle_client(struct fsmonitor_daemon_state *state,
 	trace2_data_intmax("fsmonitor", the_repository, "response/count/duplicates", duplicates);
 
 cleanup:
+	kh_destroy_str(shown);
 	strbuf_release(&response_token);
 	strbuf_release(&requested_token_id);
 	strbuf_release(&payload);

base-commit: 7c7698a654a7a0031f65b0ab0c1c4e438e95df60

Signature · 1 line
gitgitgadget
#3 lore raw
Quoted 9 lines · Paul Tarjan via GitGitGadget

From: Paul Tarjan <[email protected]>

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. However, kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself, which is allocated by kh_init_str() via xcalloc. This caused a 40-byte leak per client request.

Quoted 7 lines

Fix by using kh_destroy_str() which properly frees both internal arrays and the struct itself. Also move the cleanup to the cleanup section and initialize shown to NULL so that kh_destroy_str() is safe to call on all exit paths.

---

This is already in v4 of the other larger fsmonitor-linux patch, right?

Thanks.

#4 lore raw
Quoted 17 lines · Junio C Hamano
Quoted 14 lines · Paul Tarjan via GitGitGadget

From: Paul Tarjan <[email protected]>

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. However, kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself, which is allocated by kh_init_str() via xcalloc. This caused a 40-byte leak per client request.

Fix by using kh_destroy_str() which properly frees both internal arrays and the struct itself. Also move the cleanup to the cleanup section and initialize shown to NULL so that kh_destroy_str() is safe to call on all exit paths.

Quoted 5 lines
Quoted 2 lines

---

This is already in v4 of the other larger fsmonitor-linux patch, right?

Correct. I sent it separately since it is currently a bug in existing code and you might want to merge it sooner.

Quoted 3 lines

Thanks.

#5 lore raw
Quoted 18 lines · Paul Tarjan
Quoted 17 lines · Junio C Hamano
Quoted 14 lines · Paul Tarjan via GitGitGadget

From: Paul Tarjan <[email protected]>

The do_handle_client() function allocates a khash table to de-duplicate pathnames when responding to client requests. However, kh_release_str() was used instead of kh_destroy_str(). The release function only frees internal arrays (flags, keys, vals) but not the struct itself, which is allocated by kh_init_str() via xcalloc. This caused a 40-byte leak per client request.

Fix by using kh_destroy_str() which properly frees both internal arrays and the struct itself. Also move the cleanup to the cleanup section and initialize shown to NULL so that kh_destroy_str() is safe to call on all exit paths.

Quoted 8 lines
Quoted 5 lines
Quoted 2 lines

---

This is already in v4 of the other larger fsmonitor-linux patch, right?

Correct. I sent it separately since it is currently a bug in existing code and you might want to merge it sooner.

Thanks.