line-log: fix several memory leaks
As described in "line-log.c" itself, the code is "leaking like a sieve". These leaks are all of rather trivial nature, so this commit plugs them without going too much into details for each of those leaks. The leaks are hit by t4211, but plugging them alone does not make the full test suite pass. The remaining leaks are unrelated to the line-log subsystem. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Sep 30, 2024 at 11:13 UTC
5ce08ed4fbb60c984f46632aaa30d8f781e57e56
1 file changed
+35
-19
line-log.c
+35
-19
@@ -248,8 +248,10 @@ static void line_log_data_init(struct line_log_data *r)
248
static void line_log_data_clear(struct line_log_data *r)
249
{
250
range_set_release(&r->ranges);
251
+ free(r->path);
252
if (r->pair)
253
diff_free_filepair(r->pair);
254
+ diff_ranges_release(&r->diff);
255
}
256
257
static void free_line_log_data(struct line_log_data *r)
@@ -571,7 +573,8 @@ parse_lines(struct repository *r, struct commit *commit,
573
struct line_log_data *p;
574
575
for_each_string_list_item(item, args) {
574
- const char *name_part, *range_part;
576
+ const char *name_part;
577
+ char *range_part;
578
char *full_name;
579
struct diff_filespec *spec;
580
long begin = 0, end = 0;
@@ -615,6 +618,7 @@ parse_lines(struct repository *r, struct commit *commit,
618
619
free_filespec(spec);
620
FREE_AND_NULL(ends);
621
+ free(range_part);
622
}
623
624
for (p = ranges; p; p = p->next)
@@ -760,15 +764,13 @@ static void parse_pathspec_from_ranges(struct pathspec *pathspec,
764
{
765
struct line_log_data *r;
766
struct strvec array = STRVEC_INIT;
763
- const char **paths;
767
768
for (r = range; r; r = r->next)
769
strvec_push(&array, r->path);
767
- paths = strvec_detach(&array);
770
769
- parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL, "", paths);
770
- /* strings are now owned by pathspec */
771
- free(paths);
771
+ parse_pathspec(pathspec, 0, PATHSPEC_PREFER_FULL, "", array.v);
772
+
773
+ strvec_clear(&array);
774
}
775
776
void line_log_init(struct rev_info *rev, const char *prefix, struct string_list *args)
@@ -781,6 +783,8 @@ void line_log_init(struct rev_info *rev, const char *prefix, struct string_list
783
add_line_range(rev, commit, range);
784
785
parse_pathspec_from_ranges(&rev->diffopt.pathspec, range);
786
+
787
+ free_line_log_data(range);
788
}
789
790
static void move_diff_queue(struct diff_queue_struct *dst,
@@ -1131,10 +1135,18 @@ static int process_all_files(struct line_log_data **range_out,
1135
while (rg && strcmp(rg->path, pair->two->path))
1136
rg = rg->next;
1137
assert(rg);
1138
+ if (rg->pair)
1139
+ diff_free_filepair(rg->pair);
1140
rg->pair = diff_filepair_dup(queue->queue[i]);
1141
+ diff_ranges_release(&rg->diff);
1142
memcpy(&rg->diff, pairdiff, sizeof(struct diff_ranges));
1143
+ FREE_AND_NULL(pairdiff);
1144
+ }
1145
+
1146
+ if (pairdiff) {
1147
+ diff_ranges_release(pairdiff);
1148
+ free(pairdiff);
1149
}
1137
- free(pairdiff);
1150
}
1151
1152
return changed;
@@ -1212,12 +1224,13 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
1224
struct commit_list *p;
1225
int i;
1226
int nparents = commit_list_count(commit->parents);
1227
+ int ret;
1228
1229
if (nparents > 1 && rev->first_parent_only)
1230
nparents = 1;
1231
1232
ALLOC_ARRAY(diffqueues, nparents);
1220
- ALLOC_ARRAY(cand, nparents);
1233
+ CALLOC_ARRAY(cand, nparents);
1234
ALLOC_ARRAY(parents, nparents);
1235
1236
p = commit->parents;
@@ -1229,7 +1242,6 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
1242
1243
for (i = 0; i < nparents; i++) {
1244
int changed;
1232
- cand[i] = NULL;
1245
changed = process_all_files(&cand[i], rev, &diffqueues[i], range);
1246
if (!changed) {
1247
/*
@@ -1237,13 +1249,10 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
1249
* don't follow any other path in history
1250
*/
1251
add_line_range(rev, parents[i], cand[i]);
1240
- clear_commit_line_range(rev, commit);
1252
commit_list_append(parents[i], &commit->parents);
1242
- free(parents);
1243
- free(cand);
1244
- free_diffqueues(nparents, diffqueues);
1245
- /* NEEDSWORK leaking like a sieve */
1246
- return 0;
1253
+
1254
+ ret = 0;
1255
+ goto out;
1256
}
1257
}
1258
@@ -1251,18 +1260,25 @@ static int process_ranges_merge_commit(struct rev_info *rev, struct commit *comm
1260
* No single parent took the blame. We add the candidates
1261
* from the above loop to the parents.
1262
*/
1254
- for (i = 0; i < nparents; i++) {
1263
+ for (i = 0; i < nparents; i++)
1264
add_line_range(rev, parents[i], cand[i]);
1256
- }
1265
1266
+ ret = 1;
1267
+
1268
+out:
1269
clear_commit_line_range(rev, commit);
1270
free(parents);
1271
+ for (i = 0; i < nparents; i++) {
1272
+ if (!cand[i])
1273
+ continue;
1274
+ line_log_data_clear(cand[i]);
1275
+ free(cand[i]);
1276
+ }
1277
free(cand);
1278
free_diffqueues(nparents, diffqueues);
1262
- return 1;
1279
+ return ret;
1280
1281
/* NEEDSWORK evil merge detection stuff */
1265
- /* NEEDSWORK leaking like a sieve */
1282
}
1283
1284
int line_log_process_ranges_arbitrary_commit(struct rev_info *rev, struct commit *commit)