Re: [PATCH v3 22/22] builtin/diff: free symmetric diff members
- From
Patrick Steinhardt <ps@pks.im>
- Date
- Aug 14, 2024, 05:01 UTC
- Message-ID
- <Zrw6M7wvPFfzv3fO@tanuki>
- In-Reply-To
- <xmqq1q2s8k56.fsf@gitster.g>
On Tue, Aug 13, 2024 at 09:25:41AM -0700, Junio C Hamano wrote:
Show 22 quoted lines
> Patrick Steinhardt <ps@pks.im> writes:
>
> > We populate a `struct symdiff` in case the user has requested a
> > symmetric diff. Part of this is to populate a `skip` bitmap that
> > indicates which commits shall be ignored in the diff. But while this
> > bitmap is dynamically allocated, we never free it.
> >
> > Fix this by introducing and calling a new `symdiff_release()` function
> > that does this for us.
>
> OK.
>
> > +static void symdiff_release(struct symdiff *sdiff)
> > +{
> > + if (!sdiff)
> > + return;
> > + bitmap_free(sdiff->skip);
> > +}
>
> Hmph, wouldn't it be a BUG if any caller feeds a NULL pointer to it,
> though? When symdiff was prepared but not used, sdiff->skip will be
> NULL but sdiff is never NULL even in such a case.Good point. It does make sense for `_free()` functions to handle NULL pointers, but doesn't quite for `_release()` ones.
Show 23 quoted lines
> > @@ -398,7 +405,7 @@ int cmd_diff(int argc, const char **argv, const char *prefix)
> > struct object_array_entry *blob[2];
> > int nongit = 0, no_index = 0;
> > int result;
> > - struct symdiff sdiff;
> > + struct symdiff sdiff = {0};
>
> And symdiff_prepare() at least clears its .skip member to NULL, so
> this pre-initialization is probably not needed. If we are preparing
> ourselves for future changes of the flow in this function (e.g.
> goto's that jump to the clean-up label from which symdiff_release()
> is always called, even when we did not call symdiff_prepare() on
> this thing), this is probably not sufficient to convey that
> intention (instead I'd use an explicit ".skip = NULL" to say "we
> might not even call _prepare() but this one is prepared to be passed
> to _release() even in such a case").
>
> Given that there is no such goto exists, and that _prepare() always
> sets up the .skip member appropriately, I wonder if we are much
> better off leaving sdiff uninitialized at the declaration site here.
> If we add such a goto that bypasses _prepare() in the future, the
> compiler will notice that we are passing an uninitialized sdiff to
> _release(), no?You'd hope it does, but it certainly depends on your compiler flags. Various hardening flags for example implicitly initialize variables, and I have a feeling that this also causes them to not emit any warnings anymore. At least I only spot such warnings in CI.
In any case, yes, we can drop the initialization here.
Patrick