diff options
author | Namhyung Kim <namhyung.kim@lge.com> | 2013-04-01 07:35:17 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2013-05-28 09:23:52 -0400 |
commit | 26353a61b977e57b58dd3555bc0422fea46c5ad6 (patch) | |
tree | c6fe9a8d16effc5284ff44c1be0879e7adb8ad41 /tools | |
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>
Diffstat (limited to 'tools')
-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 bd0ca81eeaca..d9f2de3e81fe 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, | |||
187 | for (i = 0; i < sample->branch_stack->nr; i++) { | 187 | for (i = 0; i < sample->branch_stack->nr; i++) { |
188 | if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) | 188 | if (rep->hide_unresolved && !(bi[i].from.sym && bi[i].to.sym)) |
189 | continue; | 189 | continue; |
190 | |||
191 | err = -ENOMEM; | ||
192 | |||
190 | /* | 193 | /* |
191 | * The report shows the percentage of total branches captured | 194 | * The report shows the percentage of total branches captured |
192 | * and not events sampled. Thus we use a pseudo period of 1. | 195 | * 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, | |||
195 | &bi[i], 1, 1); | 198 | &bi[i], 1, 1); |
196 | if (he) { | 199 | if (he) { |
197 | struct annotation *notes; | 200 | struct annotation *notes; |
198 | err = -ENOMEM; | ||
199 | bx = he->branch_info; | 201 | bx = he->branch_info; |
200 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { | 202 | if (bx->from.sym && use_browser == 1 && sort__has_sym) { |
201 | notes = symbol__annotation(bx->from.sym); | 203 | notes = symbol__annotation(bx->from.sym); |
@@ -226,11 +228,12 @@ static int perf_report__add_branch_hist_entry(struct perf_tool *tool, | |||
226 | } | 228 | } |
227 | evsel->hists.stats.total_period += 1; | 229 | evsel->hists.stats.total_period += 1; |
228 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); | 230 | hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); |
229 | err = 0; | ||
230 | } else | 231 | } else |
231 | return -ENOMEM; | 232 | goto out; |
232 | } | 233 | } |
234 | err = 0; | ||
233 | out: | 235 | out: |
236 | free(bi); | ||
234 | return err; | 237 | return err; |
235 | } | 238 | } |
236 | 239 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 6b32721f829a..9438d576459d 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) | |||
292 | he->ms.map->referenced = true; | 292 | he->ms.map->referenced = true; |
293 | 293 | ||
294 | if (he->branch_info) { | 294 | if (he->branch_info) { |
295 | /* | ||
296 | * This branch info is (a part of) allocated from | ||
297 | * machine__resolve_bstack() and will be freed after | ||
298 | * adding new entries. So we need to save a copy. | ||
299 | */ | ||
300 | he->branch_info = malloc(sizeof(*he->branch_info)); | ||
301 | if (he->branch_info == NULL) { | ||
302 | free(he); | ||
303 | return NULL; | ||
304 | } | ||
305 | |||
306 | memcpy(he->branch_info, template->branch_info, | ||
307 | sizeof(*he->branch_info)); | ||
308 | |||
295 | if (he->branch_info->from.map) | 309 | if (he->branch_info->from.map) |
296 | he->branch_info->from.map->referenced = true; | 310 | he->branch_info->from.map->referenced = true; |
297 | if (he->branch_info->to.map) | 311 | if (he->branch_info->to.map) |