diff: improve lifecycle management of diff queues

The lifecycle management of diff queues is somewhat confusing:

  - For most of the part this can be attributed to `DIFF_QUEUE_CLEAR()`,
    which does not release any memory but rather initializes the queue,
    only. This is in contrast to our common naming schema, where
    "clearing" means that we release underlying memory and then
    re-initialize the data structure such that it is ready to use.

  - A second offender is `diff_free_queue()`, which does not free the
    queue structure itself. It is rather a release-style function.

Refactor the code to make things less confusing. `DIFF_QUEUE_CLEAR()` is
replaced by `DIFF_QUEUE_INIT` and `diff_queue_init()`, while
`diff_free_queue()` is replaced by `diff_queue_release()`. While on it,
adapt callsites where we call `DIFF_QUEUE_CLEAR()` with the intent to
release underlying memory to instead call `diff_queue_clear()` to fix
memory leaks.

This memory leak is exposed by t4211, but plugging it alone does not
make the whole test suite pass.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Patrick Steinhardt
2024-09-30 11:13:45 +02:00
committed by Junio C Hamano
parent fdf972a9df
commit a5aecb2cdc
10 changed files with 32 additions and 47 deletions

22
diff.c
View File

@ -5983,11 +5983,18 @@ void diff_free_filepair(struct diff_filepair *p)
free(p);
}
void diff_free_queue(struct diff_queue_struct *q)
void diff_queue_init(struct diff_queue_struct *q)
{
struct diff_queue_struct blank = DIFF_QUEUE_INIT;
memcpy(q, &blank, sizeof(*q));
}
void diff_queue_clear(struct diff_queue_struct *q)
{
for (int i = 0; i < q->nr; i++)
diff_free_filepair(q->queue[i]);
free(q->queue);
diff_queue_init(q);
}
const char *diff_aligned_abbrev(const struct object_id *oid, int len)
@ -6551,8 +6558,7 @@ int diff_flush_patch_id(struct diff_options *options, struct object_id *oid, int
struct diff_queue_struct *q = &diff_queued_diff;
int result = diff_get_patch_id(options, oid, diff_header_only);
diff_free_queue(q);
DIFF_QUEUE_CLEAR(q);
diff_queue_clear(q);
return result;
}
@ -6835,8 +6841,7 @@ void diff_flush(struct diff_options *options)
}
free_queue:
diff_free_queue(q);
DIFF_QUEUE_CLEAR(q);
diff_queue_clear(q);
diff_free(options);
/*
@ -6867,9 +6872,7 @@ static void diffcore_apply_filter(struct diff_options *options)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
DIFF_QUEUE_CLEAR(&outq);
struct diff_queue_struct outq = DIFF_QUEUE_INIT;
if (!options->filter)
return;
@ -6962,8 +6965,7 @@ static void diffcore_skip_stat_unmatch(struct diff_options *diffopt)
{
int i;
struct diff_queue_struct *q = &diff_queued_diff;
struct diff_queue_struct outq;
DIFF_QUEUE_CLEAR(&outq);
struct diff_queue_struct outq = DIFF_QUEUE_INIT;
for (i = 0; i < q->nr; i++) {
struct diff_filepair *p = q->queue[i];