diff options
author | Namhyung Kim <namhyung.kim@lge.com> | 2013-04-01 20:35:17 +0900 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-05-28 16:23:52 +0300 |
commit | 26353a61b977e57b58dd3555bc0422fea46c5ad6 (patch) | |
tree | c6fe9a8d16effc5284ff44c1be0879e7adb8ad41 | |
parent | 6956664a5c4c32d5aa48fe96d5e2421a3e3f72d5 (diff) |
perf hists: Fix an invalid memory free on he->branch_info
The branch info was allocated for the whole stack and passed matching
hist entry for each level during processing samples. Thus when a hist
entry tries to free its branch info like in hists__collapse_insert_entry
it'll face following error.
*** glibc detected *** perf: munmap_chunk(): invalid pointer: 0x00000000014e9d20 ***
======= Backtrace: =========
/lib64/libc.so.6[0x387d47ae16]
perf[0x4923bd]
perf(cmd_report+0xd68)[0x432a08]
perf[0x41a663]
perf(main+0x58f)[0x419eaf]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x387d421735]
perf[0x419f95]
Fix it by allocating and copying branch info for each new hist entry.
Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/r/1364816125-12212-2-git-send-email-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
-rw-r--r-- | tools/perf/builtin-report.c | 9 | ||||
-rw-r--r-- | tools/perf/util/hist.c | 14 |
2 files changed, 20 insertions, 3 deletions
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bd0ca81eeac..d9f2de3e81f 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -187,6 +187,9 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, for (i = 0; i < sample->branch_stack->nr; i++) { if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) continue; + + err = -ENOMEM; + /* * The report shows the percentage of total branches captured * and not events sampled. Thus we use a pseudo period of 1. @@ -195,7 +198,6 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, &bi[i], 1, 1); if (he) { struct annotation *notes; - err = -ENOMEM; bx = he->branch_info; if (bx->from.sym && use_browser == 1 && sort__has_sym) { notes = symbol__annotation(bx->from.sym); @@ -226,11 +228,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, } evsel->hists.stats.total_period += 1; hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); - err = 0; } else - return -ENOMEM; + goto out; } + err = 0; out: + free(bi); return err; } diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6b32721f829..9438d576459 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -292,6 +292,20 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template) he->ms.map->referenced = true; if (he->branch_info) { + /* + * This branch info is (a part of) allocated from + * machine__resolve_bstack() and will be freed after + * adding new entries. So we need to save a copy. + */ + he->branch_info = malloc(sizeof(*he->branch_info)); + if (he->branch_info == NULL) { + free(he); + return NULL; + } + + memcpy(he->branch_info, template->branch_info, + sizeof(*he->branch_info)); + if (he->branch_info->from.map) he->branch_info->from.map->referenced = true; if (he->branch_info->to.map) |