bin/167103: dtrace(1) generates core dump trying to build perl with dtrace enabled
Mark Johnston
markjdb at gmail.com
Thu Nov 22 21:30:01 UTC 2012
The following reply was made to PR bin/167103; it has been noted by GNATS.
From: Mark Johnston <markjdb at gmail.com>
To: bug-followup at FreeBSD.org, swills at FreeBSD.org
Cc:
Subject: Re: bin/167103: dtrace(1) generates core dump trying to build perl
with dtrace enabled
Date: Thu, 22 Nov 2012 16:22:54 -0500
--9amGYk9869ThD9tj
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
The assertion failure is the result of a double free in
dt_link.c:process_obj, and it's basically happening because libdtrace is
dependant on some internal behaviour of Solaris' libelf.
In the block between lines 1358 and 1415, some buffers are injected into
a couple of libelf structures (data_str and data_sym). On Solaris, it
looks like the overwritten pointers are just pointers into a larger
buffer; on FreeBSD, they're allocated on their own and then freed in
elf_close(3). Thus the injected buffers get freed by both libdtrace and
libelf.
I think the right fix is to just #ifdef the free()s out. One could
implement a portable fix by saving pointers to the original buffers
somewhere (probably in the struct dt_link_pair) and restore them before
calling elf_close(). But I don't think fixes to FreeBSD's dtrace port
are going to go back upstream anyway, so I've attached a patch with the
simple fix.
To reproduce this on a recent CURRENT, it'll be necessary to follow one
of the workarounds described in bin/171678 first.
Now, in the case of perl, we immediately run into another problem after
my patch. The build then fails with:
dtrace: failed to link script perldtrace.d: an error was
encountered while processing pp_ctl.o
It looks like this is caused by an unrelated dependance on Solaris
libelf's behaviour, but I haven't pinned it down yet.
Thanks,
-Mark
--9amGYk9869ThD9tj
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="dtrace_double_free.patch.txt"
diff --git a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
index 2d0428a..00c52ab 100644
--- a/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
+++ b/cddl/contrib/opensolaris/lib/libdtrace/common/dt_link.c
@@ -1092,8 +1092,10 @@ dt_link_error(dtrace_hdl_t *dtp, Elf *elf, int fd, dt_link_pair_t *bufs,
while ((pair = bufs) != NULL) {
bufs = pair->dlp_next;
+#if !defined(__FreeBSD__)
dt_free(dtp, pair->dlp_str);
dt_free(dtp, pair->dlp_sym);
+#endif
dt_free(dtp, pair);
}
@@ -1385,6 +1387,9 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
bufs = pair;
bcopy(data_str->d_buf, pair->dlp_str, data_str->d_size);
+#if defined( __FreeBSD__)
+ free(data_str->d_buf);
+#endif
data_str->d_buf = pair->dlp_str;
data_str->d_size += len;
(void) elf_flagdata(data_str, ELF_C_SET, ELF_F_DIRTY);
@@ -1393,6 +1398,9 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
(void) gelf_update_shdr(scn_str, &shdr_str);
bcopy(data_sym->d_buf, pair->dlp_sym, data_sym->d_size);
+#if defined(__FreeBSD__)
+ free(data_sym->d_buf);
+#endif
data_sym->d_buf = pair->dlp_sym;
data_sym->d_size += nsym * symsize;
(void) elf_flagdata(data_sym, ELF_C_SET, ELF_F_DIRTY);
@@ -1576,8 +1584,10 @@ process_obj(dtrace_hdl_t *dtp, const char *obj, int *eprobesp)
#endif
while ((pair = bufs) != NULL) {
bufs = pair->dlp_next;
+#if !defined(__FreeBSD__)
dt_free(dtp, pair->dlp_str);
dt_free(dtp, pair->dlp_sym);
+#endif
dt_free(dtp, pair);
}
--9amGYk9869ThD9tj--
More information about the freebsd-bugs
mailing list