Commit-ID:  26353a61b977e57b58dd3555bc0422fea46c5ad6
Gitweb:     http://git.kernel.org/tip/26353a61b977e57b58dd3555bc0422fea46c5ad6
Author:     Namhyung Kim <namhyung....@lge.com>
AuthorDate: Mon, 1 Apr 2013 20:35:17 +0900
Committer:  Arnaldo Carvalho de Melo <a...@redhat.com>
CommitDate: Tue, 28 May 2013 16:23:52 +0300

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 <namhy...@kernel.org>
Cc: Andi Kleen <a...@firstfloor.org>
Cc: David Ahern <dsah...@gmail.com>
Cc: Ingo Molnar <mi...@kernel.org>
Cc: Jiri Olsa <jo...@redhat.com>
Cc: Paul Mackerras <pau...@samba.org>
Cc: Peter Zijlstra <a.p.zijls...@chello.nl>
Cc: Stephane Eranian <eran...@google.com>
Link: 
http://lkml.kernel.org/r/1364816125-12212-2-git-send-email-namhy...@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <a...@redhat.com>
---
 tools/perf/builtin-report.c |  9 ++++++---
 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 bd0ca81..d9f2de3 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 6b32721..9438d57 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)
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to