From 5e6e8dc7860374d79bad3e2a3ade0c2d391bbad6 Mon Sep 17 00:00:00 2001 From: Taylor Blau Date: Mon, 11 May 2026 20:47:12 -0400 Subject: [PATCH] pack-bitmap: prevent pattern leak on pseudo-merge re-assignment When "bitmapPseudoMerge.*.pattern" appears more than once for the same group, `pseudo_merge_config()` frees the old `regex_t *` pointer but does not call `regfree()` on it first. This leaks whatever internal state `regcomp()` allocated. The final cleanup path in `pseudo_merge_group_release()` does call `regfree()` before `free()`, so only the intermediate replacement is affected. Fix this by guarding the replacement with a NULL check and calling `regfree()` before `free()` when the pointer is non-NULL. Signed-off-by: Taylor Blau Signed-off-by: Junio C Hamano --- pseudo-merge.c | 5 ++++- t/t5333-pseudo-merge-bitmaps.sh | 29 +++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/pseudo-merge.c b/pseudo-merge.c index 75bed04360..22b8600d68 100644 --- a/pseudo-merge.c +++ b/pseudo-merge.c @@ -150,7 +150,10 @@ static int pseudo_merge_config(const char *var, const char *value, if (!strcmp(key, "pattern")) { struct strbuf re = STRBUF_INIT; - free(group->pattern); + if (group->pattern) { + regfree(group->pattern); + free(group->pattern); + } if (*value != '^') strbuf_addch(&re, '^'); strbuf_addstr(&re, value); diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh index 5bfbbd4214..305d677108 100755 --- a/t/t5333-pseudo-merge-bitmaps.sh +++ b/t/t5333-pseudo-merge-bitmaps.sh @@ -662,4 +662,33 @@ test_expect_success 'sampleRate=0 does not cause division by zero' ' ) ' +test_expect_success 'duplicate pseudo-merge pattern does not leak' ' + test_when_finished "rm -fr pseudo-merge-dup-pattern" && + git init pseudo-merge-dup-pattern && + ( + cd pseudo-merge-dup-pattern && + + test_commit_bulk 64 && + tag_everything && + git repack -ad && + + pack=$(ls .git/objects/pack/pack-*.pack) && + + # Set the same group'\''s pattern twice. The second + # assignment should cleanly release the compiled regex + # from the first without leaking. + git config bitmapPseudoMerge.test.pattern "refs/tags/" && + git config --add bitmapPseudoMerge.test.pattern "refs/tags/" && + git config bitmapPseudoMerge.test.maxMerges 1 && + git config bitmapPseudoMerge.test.threshold now && + git config bitmapPseudoMerge.test.stableThreshold never && + + git rev-parse HEAD~63 >in && + test-tool bitmap write "$(basename $pack)" merges && + test_line_count = 1 merges + ) +' + test_done