[DTrace-devel] [PATCH 6/8] btf: fix memory leaks
Kris Van Hees
kris.van.hees at oracle.com
Thu Apr 4 20:12:18 UTC 2024
On Thu, Apr 04, 2024 at 08:58:36PM +0100, Nick Alcock wrote:
> On 3 Apr 2024, Kris Van Hees via DTrace-devel said:
>
> > Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
>
> A bit more to do :(
>
> > ---
> > libdtrace/dt_btf.c | 21 ++++++++++++++++-----
> > libdtrace/dt_btf.h | 1 +
> > libdtrace/dt_module.c | 2 +-
> > libdtrace/dt_open.c | 3 +++
> > 4 files changed, 21 insertions(+), 6 deletions(-)
> >
> > diff --git a/libdtrace/dt_btf.c b/libdtrace/dt_btf.c
> > index 3f713632..020c7877 100644
> > --- a/libdtrace/dt_btf.c
> > +++ b/libdtrace/dt_btf.c
> > @@ -240,7 +240,7 @@ dt_btf_load(dtrace_hdl_t *dtp, const char *fn)
> >
> > fp = fopen(fn, "rb");
> > if (fp == NULL)
> > - return dt_btf_set_load_errno(dtp, errno);
> > + goto err;
> >
> > /* First see whether this might be a file with raw BTF data. */
> > if (fread(&hdr, 1, sizeof(hdr), fp) < sizeof(hdr))
> > @@ -317,12 +317,12 @@ elf_fail_no_end:
> > dt_btf_error(dtp, 0, "BTF: %s", elf_errmsg(err));
> > fclose(fp);
> >
> > - return NULL;
> > -
> > fail:
> > dt_free(dtp, data);
> > +
> > +err:
> > + dt_free(dtp, btf);
>
> This should be a dt_btf_destroy(), since you might have allocated
> btf->data by the time you enter elf_fail.
In that case the dt_free(dtp, data) got executed already.
> There's another leak above:
>
> data = dt_alloc(dtp, st.st_size);
> if (data == NULL)
> goto fail;
>
> if (fread(data, 1, st.st_size, fp) < st.st_size)
> goto fail;
>
> That second fail has allocated 'data' but not yet assigned it to
> btf->data, so even if you *do* use dt_btf_destroy() where I flagged, it
> wouldn't free it...
Again, that is why we have the dt_free(dtp, data);
> > dt_btf_set_errno(dtp, err ? err : errno);
> > - fclose(fp);
>
> ... this looks like you've turned a leak of btf into an fd leak of fp by
> everything going down the fail path (all of which are entered before the
> fclose() of fp on the non-fail paths above).
Ah yes, I forgot to move the fclose(fp) to the fail: label.
> In summary, error paths are evil!
>
>
>
> > @@ -752,7 +763,7 @@ dt_btf_load_module(dtrace_hdl_t *dtp, dt_module_t *dmp)
> > snprintf(fn, sizeof(fn), "/sys/kernel/btf/%s", dmp->dm_name);
> > btf = dt_btf_load_file(dtp, fn);
> >
> > - if (btf && strcmp(dmp->dm_name, "vmlinux") == 0)
> > + if (btf && !dtp->dt_shared_btf && strcmp(dmp->dm_name, "vmlinux") == 0)
> > dtp->dt_shared_btf = btf;
>
> Is there some danger that dt_btf_load_module() wil be called on vmlinux
> more than once? That's the only situation in which this change would
> constitute a leak fix.
>
> > + if (dtp->dt_shared_btf != NULL)
> > + dt_btf_destroy(dtp, dtp->dt_shared_btf);
>
> Unnecessary != NULL check. (It's unnecessary in the CTF case below, too.)
>
> --
> NULL && (void)
More information about the DTrace-devel
mailing list