perf tools: Splice events onto evlist even on error
authorIan Rogers <irogers@google.com>
Fri, 25 Oct 2019 18:08:22 +0000 (11:08 -0700)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Wed, 6 Nov 2019 18:49:39 +0000 (15:49 -0300)
If event parsing fails the event list is leaked, instead splice the list
onto the out result and let the caller cleanup.

An example input for parse_events found by libFuzzer that reproduces
this memory leak is 'm{'.

Signed-off-by: Ian Rogers <irogers@google.com>
Acked-by: Jiri Olsa <jolsa@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Martin KaFai Lau <kafai@fb.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Song Liu <songliubraving@fb.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Yonghong Song <yhs@fb.com>
Cc: bpf@vger.kernel.org
Cc: clang-built-linux@googlegroups.com
Cc: netdev@vger.kernel.org
Link: http://lore.kernel.org/lkml/20191025180827.191916-5-irogers@google.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/util/parse-events.c

index db882f630f7e8e6bb7993bfb883e79b4e61c88f8..d36b8129b27a2978dae2e2576ffc9e8828a73455 100644 (file)
@@ -1927,15 +1927,20 @@ int parse_events(struct evlist *evlist, const char *str,
 
        ret = parse_events__scanner(str, &parse_state, PE_START_EVENTS);
        perf_pmu__parse_cleanup();
+
+       if (!ret && list_empty(&parse_state.list)) {
+               WARN_ONCE(true, "WARNING: event parser found nothing\n");
+               return -1;
+       }
+
+       /*
+        * Add list to the evlist even with errors to allow callers to clean up.
+        */
+       perf_evlist__splice_list_tail(evlist, &parse_state.list);
+
        if (!ret) {
                struct evsel *last;
 
-               if (list_empty(&parse_state.list)) {
-                       WARN_ONCE(true, "WARNING: event parser found nothing\n");
-                       return -1;
-               }
-
-               perf_evlist__splice_list_tail(evlist, &parse_state.list);
                evlist->nr_groups += parse_state.nr_groups;
                last = evlist__last(evlist);
                last->cmdline_group_boundary = true;