[DTrace-devel] [PATCH v2 05/14] probe: improve dt_probe_lookup2()

Kris Van Hees kris.van.hees at oracle.com
Tue Oct 29 19:50:38 UTC 2024


On Mon, Oct 28, 2024 at 09:17:54PM +0000, Nick Alcock via DTrace-devel wrote:
> This function had numerous problems:
> 
>  - it broke _FORTIFY_SOURCE due to using a function that snprintf()ed
>    with a size of INT_MAX, into a much smaller alloca()ed buffer
>  - it claimed to call down to the dtrace kernel module for a probe
>    description (long obsolete)
>  - it invariably leaked the probe description it constructed by calling
>    dtrace_xstr2desc()
>  - it did meaningless errno testing to determine whether to return
>    EDT_NOPROBE on error, which more or less led to EDT_NOPROBE never
>    being returned even though it should always be in this case (there
>    is no other cause for the ID hash lookup failing).
> 
> Fix the lot: while we're at it, implement a dt_desc_destroy() to
> undo the strdup()s done by dtrace_xstr2desc(), and use it additionally
> in dt_probe_destroy() instead of an identical sequence of dt_free()s.
> 
> Bug: https://github.com/oracle/dtrace-utils/issues/78
> Signed-off-by: Nick Alcock <nick.alcock at oracle.com>
> ---
>  libdtrace/dt_impl.h  |  2 ++
>  libdtrace/dt_probe.c | 44 +++++++++++++-------------------------------
>  libdtrace/dt_subr.c  | 10 ++++++++++
>  3 files changed, 25 insertions(+), 31 deletions(-)
> 
> diff --git a/libdtrace/dt_impl.h b/libdtrace/dt_impl.h
> index 340dc1960c5e..d11ad2839f8e 100644
> --- a/libdtrace/dt_impl.h
> +++ b/libdtrace/dt_impl.h
> @@ -759,6 +759,8 @@ extern dtrace_difo_t *dt_difo_copy(dtrace_hdl_t *dtp, const dtrace_difo_t *odp);
>  extern int dt_consume_init(dtrace_hdl_t *);
>  extern void dt_consume_fini(dtrace_hdl_t *);
>  
> +extern void dt_desc_destroy(dtrace_hdl_t *dtp, dtrace_probedesc_t *);

I think it would be better to let dt_desc_destroy() take a third arg, to
indicate whether the desc itself should be free'd as well or whether it
should be left alone.

That avoids calling it and then following it up with a dt_free() on the desc.

> +
>  extern dtrace_datadesc_t *dt_datadesc_hold(dtrace_datadesc_t *ddp);
>  extern void dt_datadesc_release(dtrace_hdl_t *, dtrace_datadesc_t *);
>  extern dtrace_datadesc_t *dt_datadesc_create(dtrace_hdl_t *);
> diff --git a/libdtrace/dt_probe.c b/libdtrace/dt_probe.c
> index 686e2a661253..f84581687caf 100644
> --- a/libdtrace/dt_probe.c
> +++ b/libdtrace/dt_probe.c
> @@ -172,24 +172,9 @@ dt_probe_alloc_args(dt_probe_t *prp, int nargc, int xargc)
>  	}
>  }
>  
> -static size_t
> -dt_probe_keylen(const dtrace_probedesc_t *pdp)
> -{
> -	return strlen(pdp->mod) + 1 + strlen(pdp->fun) + 1 +
> -		strlen(pdp->prb) + 1;
> -}
> -
> -static char *
> -dt_probe_key(const dtrace_probedesc_t *pdp, char *s)
> -{
> -	snprintf(s, INT_MAX, "%s:%s:%s", pdp->mod, pdp->fun, pdp->prb);
> -	return s;
> -}
> -
>  /*
>   * Lookup a probe declaration based on a known provider and full or partially
> - * specified module, function, and name.  If the probe is not known to us yet,
> - * ask dtrace(7D) to match the description and then cache any useful results.
> + * specified module, function, and name.
>   */
>  dt_probe_t *
>  dt_probe_lookup2(dt_provider_t *pvp, const char *s)
> @@ -197,28 +182,28 @@ dt_probe_lookup2(dt_provider_t *pvp, const char *s)
>  	dtrace_hdl_t *dtp = pvp->pv_hdl;
>  	dtrace_probedesc_t pd;
>  	dt_ident_t *idp;
> -	size_t keylen;
>  	char *key;
>  
>  	if (dtrace_str2desc(dtp, DTRACE_PROBESPEC_NAME, s, &pd) != 0)
>  		return NULL; /* dt_errno is set for us */
>  
> -	keylen = dt_probe_keylen(&pd);
> -	key = dt_probe_key(&pd, alloca(keylen));
> +	if (asprintf(&key, "%s:%s:%s", pd.mod, pd.fun, pd.prb) == -1) {
> +		dt_set_errno(dtp, errno);
> +		goto out;
> +	}
>  
>  	/*
>  	 * If the probe is already declared, then return the dt_probe_t from
> -	 * the existing identifier.  This could come from a static declaration
> -	 * or it could have been cached from an earlier call to this function.
> +	 * the existing identifier.
>  	 */
> -	if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL)
> +	if ((idp = dt_idhash_lookup(pvp->pv_probes, key)) != NULL) {
> +		dt_desc_destroy(dtp, &pd);
>  		return idp->di_data;
> +	}
>  
> -	if (errno == ESRCH || errno == EBADF)
> -		dt_set_errno(dtp, EDT_NOPROBE);
> -	else
> -		dt_set_errno(dtp, errno);
> -
> +	dt_set_errno(dtp, EDT_NOPROBE);
> + out:
> +	dt_desc_destroy(dtp, &pd);
>  	return NULL;
>  }
>  
> @@ -387,10 +372,7 @@ dt_probe_destroy(dt_probe_t *prp)
>  	dt_free(dtp, prp->mapping);
>  	dt_free(dtp, prp->argv);
>  	if (prp->desc) {
> -		dt_free(dtp, (void *)prp->desc->prv);
> -		dt_free(dtp, (void *)prp->desc->mod);
> -		dt_free(dtp, (void *)prp->desc->fun);
> -		dt_free(dtp, (void *)prp->desc->prb);
> +		dt_desc_destroy(dtp, (dtrace_probedesc_t *)prp->desc);
>  		dt_free(dtp, (void *)prp->desc);
>  	}
>  	dt_free(dtp, prp);
> diff --git a/libdtrace/dt_subr.c b/libdtrace/dt_subr.c
> index d6aad7637fb9..72631b33a0ad 100644
> --- a/libdtrace/dt_subr.c
> +++ b/libdtrace/dt_subr.c
> @@ -175,6 +175,16 @@ dtrace_desc2str(const dtrace_probedesc_t *pdp, char *buf, size_t len)
>  	return buf;
>  }
>  
> +/* Only use on probedescs derived from dtrace_xstr2desc above. */

Why can't it used on other dtrace_probedesc_t that contain references to
memory that needs to be free'd?  I don't think that dtrace_xstr2desc() does
anything to make the desc it populates be special.

> +void
> +dt_desc_destroy(dtrace_hdl_t *dtp, dtrace_probedesc_t *pdp)
> +{
> +	dt_free(dtp, (void *) pdp->prv);
> +	dt_free(dtp, (void *) pdp->mod);
> +	dt_free(dtp, (void *) pdp->fun);
> +	dt_free(dtp, (void *) pdp->prb);
> +}
> +
>  char *
>  dtrace_attr2str(dtrace_attribute_t attr, char *buf, size_t len)
>  {
> -- 
> 2.46.0.278.g36e3a12567
> 
> 
> _______________________________________________
> DTrace-devel mailing list
> DTrace-devel at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/dtrace-devel



More information about the DTrace-devel mailing list