perf hists: Fix an invalid memory free on he->branch_info
authorNamhyung Kim <namhyung.kim@lge.com>
Mon, 1 Apr 2013 11:35:17 +0000 (20:35 +0900)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Tue, 28 May 2013 13:23:52 +0000 (16:23 +0300)
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>
tools/perf/builtin-report.c
tools/perf/util/hist.c

index bd0ca81..d9f2de3 100644 (file)
@@ -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;
 }
 
index 6b32721..9438d57 100644 (file)
@@ -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)