fetch: free "raw" string when shrinking refspec

The "--prefetch" option to git-fetch modifies the default refspec, including eliminating some entries entirely. When we drop an entry we free the strings in the refspec_item, but we forgot to free the matching string in the "raw" array of the refspec struct. There's no behavioral bug here (since we correctly shrink the raw array, too), but we're leaking the allocated string. Let's add in the leak-fix, and while we're at it drop "const" from the type of the raw string array. These strings are always allocated by refspec_append(), etc, and this makes the memory ownership more clear. This is all a bit more intimate with the refspec code than I'd like, and I suspect it would be better if each refspec_item held on to its own raw string, we had a single array, and we could use refspec_item_clear() to clean up everything. But that's a non-trivial refactoring, since refspec_item structs can be held outside of a "struct refspec", without having a matching raw string at all. So let's leave that for now and just fix the leak in the most immediate way. This lets us mark t5582 as leak-free. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Jeff King committed Sep 24, 2024 at 17:57 UTC ea4780307cc5007c6136ed216d45841d21ccfe75
4 files changed +4 -2
builtin/fetch.c
+1
@@ -456,6 +456,7 @@ static void filter_prefetch_refspec(struct refspec *rs)
456
457 free(rs->items[i].src);
458 free(rs->items[i].dst);
459 + free(rs->raw[i]);
460
461 for (j = i + 1; j < rs->nr; j++) {
462 rs->items[j - 1] = rs->items[j];
refspec.c
+1 -1
@@ -225,7 +225,7 @@ void refspec_clear(struct refspec *rs)
225 rs->nr = 0;
226
227 for (i = 0; i < rs->raw_nr; i++)
228 - free((char *)rs->raw[i]);
228 + free(rs->raw[i]);
229 FREE_AND_NULL(rs->raw);
230 rs->raw_alloc = 0;
231 rs->raw_nr = 0;
refspec.h
+1 -1
@@ -43,7 +43,7 @@ struct refspec {
43 int alloc;
44 int nr;
45
46 - const char **raw;
46 + char **raw;
47 int raw_alloc;
48 int raw_nr;
49
t/t5582-fetch-negative-refspec.sh
+1
@@ -8,6 +8,7 @@ test_description='"git fetch" with negative refspecs.
8 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
9 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
10
11 +TEST_PASSES_SANITIZE_LEAK=true
12 . ./test-lib.sh
13
14 test_expect_success setup '