[DTrace-devel] [PATCH] usdt parser: fix memory leak in provider and probe htabs
Kris Van Hees
kris.van.hees at oracle.com
Thu Jun 19 03:59:42 UTC 2025
The prvmap and prbmap hashtable implementation was lacking code to
ensure that entries are freed when the hashtables are destroyed. In
addition, the pvp->pmap hashtables were also not cleaned up.
To provide cleaner data structures and to facilitate cleanup, tracepoint
probes are now always removed from prbmap and either added to the
pvp->pmap hashtable or added to the list of tracepoints for a particular
probe. Therefore, when the prbmap is destroyed it no longer contains
any entries.
So, only pvp->pmap hashtables can contain probes. If they are function
specific, they represent a tracepoint (and may have additional
tracepoints linked to them). If they are not function specific, they
provide a probe definition and they will contain probe argument data
that needs freeing.
Signed-off-by: Kris Van Hees <kris.van.hees at oracle.com>
---
libcommon/usdt_parser_notes.c | 82 +++++++++++++++++++++++++++--------
1 file changed, 65 insertions(+), 17 deletions(-)
diff --git a/libcommon/usdt_parser_notes.c b/libcommon/usdt_parser_notes.c
index cdadf4b2..c6fc3476 100644
--- a/libcommon/usdt_parser_notes.c
+++ b/libcommon/usdt_parser_notes.c
@@ -161,7 +161,25 @@ static int prv_cmp(const dt_provider_t *p, const dt_provider_t *q) {
}
DEFINE_HE_STD_LINK_FUNCS(prv, dt_provider_t, he)
-DEFINE_HTAB_STD_OPS(prv)
+
+static void *
+prv_del_prov(dt_provider_t *head, dt_provider_t *pvp)
+{
+ head = prv_del(head, pvp);
+
+ dt_htab_destroy(pvp->pmap);
+ free(pvp);
+
+ return head;
+}
+
+static dt_htab_ops_t prv_htab_ops = {
+ .hval = (htab_hval_fn)prv_hval,
+ .cmp = (htab_cmp_fn)prv_cmp,
+ .add = (htab_add_fn)prv_add,
+ .del = (htab_del_fn)prv_del_prov,
+ .next = (htab_next_fn)prv_next
+};
static uint32_t prb_hval(const dt_probe_t *prp) {
uint32_t hval;
@@ -205,6 +223,41 @@ static int prb_cmp(const dt_probe_t *p, const dt_probe_t *q) {
DEFINE_HE_STD_LINK_FUNCS(prb, dt_probe_t, he)
DEFINE_HTAB_STD_OPS(prb)
+static void *
+prb_del_probe(dt_probe_t *head, dt_probe_t *prp)
+{
+ head = prb_del(head, prp);
+
+ /*
+ * If this is not a function-specific probe (from a prov note), free
+ * the translated arg data and the probe itself.
+ * If this is a function-specific probe (from a usdt note), walk the
+ * list of tracepoint probe, freeing each probe in the list.
+ */
+ if (prp->fun == NULL) {
+ free(prp->xargs);
+ free(prp->xmap);
+ free(prp);
+ } else {
+ dt_probe_t *nxt;
+
+ do {
+ nxt = prp->next;
+ free(prp);
+ } while ((prp = nxt) != NULL);
+ }
+
+ return head;
+}
+
+static dt_htab_ops_t pmap_htab_ops = {
+ .hval = (htab_hval_fn)prb_hval,
+ .cmp = (htab_cmp_fn)prb_cmp,
+ .add = (htab_add_fn)prb_add,
+ .del = (htab_del_fn)prb_del_probe,
+ .next = (htab_next_fn)prb_next
+};
+
/*
* Return the cummulative string length of 'cnt' consecutive 0-terminated
* strings. If skip > 0, it indicates how many extra bytes are to be skipped
@@ -252,7 +305,7 @@ parse_prov_note(int out, dof_helper_t *dhp, usdt_data_t *data,
memset(pvp, 0, sizeof(dt_provider_t));
pvp->name = prvt.name;
dt_htab_insert(prvmap, pvp);
- pvp->pmap = dt_htab_create(&prb_htab_ops);
+ pvp->pmap = dt_htab_create(&pmap_htab_ops);
} else {
usdt_error(out, EEXIST, "Duplicate provider: %s", prvt.name);
return -1;
@@ -715,30 +768,24 @@ usdt_parse_notes(int out, dof_helper_t *dhp, usdt_data_t *data)
* tracepoint probe to the provider.
* In either cases, argument data is copied.
*/
+ dt_htab_delete(prbmap, ptp);
if (prp->fun != NULL) {
ptp->next = prp->next;
- ptp->nargc = prp->nargc;
- ptp->nargs = prp->nargs;
- ptp->nargsz = prp->nargsz;
- ptp->xargc = prp->xargc;
- ptp->xargs = prp->xargs;
- ptp->xargsz = prp->xargsz;
- ptp->xmap = prp->xmap;
prp->next = ptp;
prp->ntp++;
} else {
- dt_htab_delete(prbmap, ptp);
dt_htab_insert(pvp->pmap, ptp);
ptp->ntp = 1;
- ptp->nargc = prp->nargc;
- ptp->nargs = prp->nargs;
- ptp->nargsz = prp->nargsz;
- ptp->xargc = prp->xargc;
- ptp->xargs = prp->xargs;
- ptp->xargsz = prp->xargsz;
- ptp->xmap = prp->xmap;
pvp->probec++;
}
+
+ ptp->nargc = prp->nargc;
+ ptp->nargs = prp->nargs;
+ ptp->nargsz = prp->nargsz;
+ ptp->xargc = prp->xargc;
+ ptp->xargs = prp->xargs;
+ ptp->xargsz = prp->xargsz;
+ ptp->xmap = prp->xmap;
}
/* Emit any provider that has tracepoints. */
@@ -754,6 +801,7 @@ err:
rc = -1;
out:
+ assert(dt_htab_entries(prbmap) == 0);
dt_htab_destroy(prvmap);
dt_htab_destroy(prbmap);
--
2.43.5
More information about the DTrace-devel
mailing list