diff options
author | He Kuang <hekuang@huawei.com> | 2015-04-10 17:35:00 +0800 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2015-04-10 10:13:59 -0300 |
commit | 5e78c69b72276853ac64070a010e6df64723dba9 (patch) | |
tree | 5549ea875500fe48b774b14270ba00bef039f3ef /tools | |
parent | 1060ab857f64f33a9445881fd31fa91470aeb622 (diff) | |
download | linux-stable-5e78c69b72276853ac64070a010e6df64723dba9.tar.gz linux-stable-5e78c69b72276853ac64070a010e6df64723dba9.tar.bz2 linux-stable-5e78c69b72276853ac64070a010e6df64723dba9.zip |
perf buildid-list: Fix segfault when show DSOs with hits
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@huawei.com>
Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/r/1428658500-6483-1-git-send-email-hekuang@huawei.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/util/build-id.c | 8 | ||||
-rw-r--r-- | tools/perf/util/machine.c | 4 | ||||
-rw-r--r-- | 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 f7fb2587df69..61867dff5d5a 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 9c380a2caa54..527e032e24f6 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); @@ -1256,7 +1254,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 e2faf3b47e7b..6d64cedb9d1e 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); |