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 <me@ttaylorr.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Taylor Blau committed
May 11, 2026 at 20:47 UTC
5e6e8dc7860374d79bad3e2a3ade0c2d391bbad6
2 files changed
+33
-1
pseudo-merge.c
+4
-1
@@ -150,7 +150,10 @@ static int pseudo_merge_config(const char *var, const char *value,
150
if (!strcmp(key, "pattern")) {
151
struct strbuf re = STRBUF_INIT;
152
153
- free(group->pattern);
153
+ if (group->pattern) {
154
+ regfree(group->pattern);
155
+ free(group->pattern);
156
+ }
157
if (*value != '^')
158
strbuf_addch(&re, '^');
159
strbuf_addstr(&re, value);
t/t5333-pseudo-merge-bitmaps.sh
+29
@@ -662,4 +662,33 @@ test_expect_success 'sampleRate=0 does not cause division by zero' '
662
)
663
'
664
665
+test_expect_success 'duplicate pseudo-merge pattern does not leak' '
666
+ test_when_finished "rm -fr pseudo-merge-dup-pattern" &&
667
+ git init pseudo-merge-dup-pattern &&
668
+ (
669
+ cd pseudo-merge-dup-pattern &&
670
+
671
+ test_commit_bulk 64 &&
672
+ tag_everything &&
673
+ git repack -ad &&
674
+
675
+ pack=$(ls .git/objects/pack/pack-*.pack) &&
676
+
677
+ # Set the same group'\''s pattern twice. The second
678
+ # assignment should cleanly release the compiled regex
679
+ # from the first without leaking.
680
+ git config bitmapPseudoMerge.test.pattern "refs/tags/" &&
681
+ git config --add bitmapPseudoMerge.test.pattern "refs/tags/" &&
682
+ git config bitmapPseudoMerge.test.maxMerges 1 &&
683
+ git config bitmapPseudoMerge.test.threshold now &&
684
+ git config bitmapPseudoMerge.test.stableThreshold never &&
685
+
686
+ git rev-parse HEAD~63 >in &&
687
+ test-tool bitmap write "$(basename $pack)" <in &&
688
+
689
+ test_pseudo_merges >merges &&
690
+ test_line_count = 1 merges
691
+ )
692
+'
693
+
694
test_done