[PATCH] perf buildid-list: Fix segfault when show DSOs with hits

From: He Kuang
Date: Fri Apr 10 2015 - 05:40:33 EST


commit: f3b623b8490a ("perf tools: Reference count struct thread")
appends every thread->node to dead_threads in machine__remove_thread()
and list_del_init() this node in thread__put().

perf_event__exit_del_thread() releases thread wihout using
machine__remove_thread(), and causes a NULL pointer crash when
list_del_init(&thread->node) is called. Fix this by using
machine_remove_thread() instead of using thread__put() directly.

This problem can be reproduced as following:

$ perf record ls
$ perf buildid-list --with-hits
[ 3874.195070] perf[1018]: segfault at 0 ip 00000000004b0b15 sp
00007ffc35b44780 error 6 in perf[400000+166000]
Segmentation fault

After this patch:
$ perf record ls
$ perf buildid-list --with-hits
bc23e7c3281e542650ba4324421d6acf78f4c23e /proc/kcore
643324cb0e969f30c56d660f167f84a150845511 [vdso]
0000000000000000000000000000000000000000 /bin/busybox
...

Signed-off-by: He Kuang <hekuang@xxxxxxxxxx>
---
tools/perf/util/build-id.c | 8 ++------
tools/perf/util/machine.c | 4 +---
tools/perf/util/machine.h | 1 +
3 files changed, 4 insertions(+), 9 deletions(-)

diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index f7fb258..61867df 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -59,12 +59,8 @@ static int perf_event__exit_del_thread(struct perf_tool *tool __maybe_unused,
dump_printf("(%d:%d):(%d:%d)\n", event->fork.pid, event->fork.tid,
event->fork.ppid, event->fork.ptid);

- if (thread) {
- rb_erase(&thread->rb_node, &machine->threads);
- if (machine->last_match == thread)
- thread__zput(machine->last_match);
- thread__put(thread);
- }
+ if (thread)
+ machine__remove_thread(machine, thread);

return 0;
}
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index e45c8f3..b7091c9 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -14,8 +14,6 @@
#include "unwind.h"
#include "linux/hash.h"

-static void machine__remove_thread(struct machine *machine, struct thread *th);
-
static void dsos__init(struct dsos *dsos)
{
INIT_LIST_HEAD(&dsos->head);
@@ -1253,7 +1251,7 @@ out_problem:
return 0;
}

-static void machine__remove_thread(struct machine *machine, struct thread *th)
+void machine__remove_thread(struct machine *machine, struct thread *th)
{
if (machine->last_match == th)
thread__zput(machine->last_match);
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index e2faf3b..6d64ced 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -120,6 +120,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid);
void machine__exit(struct machine *machine);
void machine__delete_threads(struct machine *machine);
void machine__delete(struct machine *machine);
+void machine__remove_thread(struct machine *machine, struct thread *th);

struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
struct addr_location *al);
--
2.3.3.220.g9ab698f

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/