[DTrace-devel] [PATCH] Fix double free of printf descriptors
eugene.loh at oracle.com
eugene.loh at oracle.com
Mon Jul 13 14:09:28 PDT 2020
From: Eugene Loh <eugene.loh at oracle.com>
A recent commit ("Ensure record descriptors get cleaned up") sought
to free printf descriptors associated with any record descriptors.
It did so by having dt_datadesc_release() loop over records, freeing
a printf descriptor (if any) for each record.
The problem was that there should be a match between dt_printf_create()
and dt_printf_destroy() calls, but in dt_cg_act_printf() the same
printf descriptor can be used for multiple records. The patch would
try to free the same printf descriptor multiple times.
For example,
# dtrace -qn 'BEGIN { printf("%d %d %d\n", 1, 2, 3); exit(0); }'
1 2 3
double free or corruption (fasttop)
# ./runtest.sh test/unittest/actions/printf/tst.conv_T.sh \
test/unittest/actions/printf/tst.conv_Y.sh \
test/unittest/builtinvar/tst.arg1to8.d \
test/unittest/inline/tst.InlineExpression.d \
test/unittest/types/tst.bitops.d \
test/unittest/actions/printf/tst.conv_T.sh: FAIL: core dumped.
test/unittest/actions/printf/tst.conv_Y.sh: FAIL: core dumped.
test/unittest/builtinvar/tst.arg1to8.d: FAIL: core dumped.
test/unittest/inline/tst.InlineExpression.d: FAIL: core dumped.
test/unittest/types/tst.bitops.d: FAIL: core dumped.
5 cases (0 PASS, 5 FAIL, 0 XPASS, 0 XFAIL, 0 SKIP)
There are also other such test failures, but they're hiding behind
XFAILs.
Fix dt_datadesc_release() to free a particular printf descriptor
only once.
Signed-off-by: Eugene Loh <eugene.loh at oracle.com>
---
libdtrace/dt_map.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/libdtrace/dt_map.c b/libdtrace/dt_map.c
index 3994ec3a..43ac1f84 100644
--- a/libdtrace/dt_map.c
+++ b/libdtrace/dt_map.c
@@ -26,13 +26,16 @@ dt_datadesc_release(dtrace_hdl_t *dtp, dtrace_datadesc_t *ddp)
{
int i;
dtrace_recdesc_t *rec;
+ void *last = NULL;
if (--ddp->dtdd_refcnt > 0)
return;
for (i = 0, rec = &ddp->dtdd_recs[0]; i < ddp->dtdd_nrecs; i++, rec++) {
- if (rec->dtrd_format != NULL)
+ if (rec->dtrd_format != NULL &&
+ rec->dtrd_format != last)
dt_printf_destroy(rec->dtrd_format);
+ last = rec->dtrd_format;
}
dt_free(dtp, ddp->dtdd_recs);
dt_free(dtp, ddp);
--
2.18.2
More information about the DTrace-devel
mailing list