Commit 07eafd4e authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo
Browse files

perf parse-event: Add init and exit to parse_event_error



parse_events() may succeed but leave string memory allocations reachable
in the error.

Add an init/exit that must be called to initialize and clean up the
error. This fixes a leak in metricgroup parse_ids.

Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: John Garry <john.garry@huawei.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20211107090002.3784612-2-irogers@google.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 6c191289
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -113,10 +113,11 @@ static int is_tracepoint_available(const char *str, struct evlist *evlist)
	struct parse_events_error err;
	int ret;

	bzero(&err, sizeof(err));
	parse_events_error__init(&err);
	ret = parse_events(evlist, str, &err);
	if (err.str)
		parse_events_error__print(&err, "tracepoint");
	parse_events_error__exit(&err);
	return ret;
}

+4 −2
Original line number Diff line number Diff line
@@ -78,7 +78,7 @@ static int evlist__count_evsel_fds(struct evlist *evlist)

static struct evlist *bench__create_evlist(char *evstr)
{
	struct parse_events_error err = { .idx = 0, };
	struct parse_events_error err;
	struct evlist *evlist = evlist__new();
	int ret;

@@ -87,14 +87,16 @@ static struct evlist *bench__create_evlist(char *evstr)
		return NULL;
	}

	parse_events_error__init(&err);
	ret = parse_events(evlist, evstr, &err);
	if (ret) {
		parse_events_error__print(&err, evstr);
		parse_events_error__exit(&err);
		pr_err("Run 'perf list' for a list of valid events\n");
		ret = 1;
		goto out_delete_evlist;
	}

	parse_events_error__exit(&err);
	ret = evlist__create_maps(evlist, &opts.target);
	if (ret < 0) {
		pr_err("Not enough memory to create thread/cpu maps\n");
+22 −16
Original line number Diff line number Diff line
@@ -1750,14 +1750,12 @@ static int add_default_attributes(void)
	(PERF_COUNT_HW_CACHE_OP_PREFETCH	<<  8) |
	(PERF_COUNT_HW_CACHE_RESULT_MISS	<< 16)				},
};
	struct parse_events_error errinfo;

	/* Set attrs if no event is selected and !null_run: */
	if (stat_config.null_run)
		return 0;

	bzero(&errinfo, sizeof(errinfo));
	if (transaction_run) {
		struct parse_events_error errinfo;
		/* Handle -T as -M transaction. Once platform specific metrics
		 * support has been added to the json files, all architectures
		 * will use this approach. To determine transaction support
@@ -1772,6 +1770,7 @@ static int add_default_attributes(void)
							 &stat_config.metric_events);
		}

		parse_events_error__init(&errinfo);
		if (pmu_have_event("cpu", "cycles-ct") &&
		    pmu_have_event("cpu", "el-start"))
			err = parse_events(evsel_list, transaction_attrs,
@@ -1783,12 +1782,13 @@ static int add_default_attributes(void)
		if (err) {
			fprintf(stderr, "Cannot set up transaction events\n");
			parse_events_error__print(&errinfo, transaction_attrs);
			return -1;
		}
		return 0;
		parse_events_error__exit(&errinfo);
		return err ? -1 : 0;
	}

	if (smi_cost) {
		struct parse_events_error errinfo;
		int smi;

		if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) {
@@ -1804,23 +1804,23 @@ static int add_default_attributes(void)
			smi_reset = true;
		}

		if (pmu_have_event("msr", "aperf") &&
		    pmu_have_event("msr", "smi")) {
			if (!force_metric_only)
				stat_config.metric_only = true;
			err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
		} else {
		if (!pmu_have_event("msr", "aperf") ||
		    !pmu_have_event("msr", "smi")) {
			fprintf(stderr, "To measure SMI cost, it needs "
				"msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
			parse_events_error__print(&errinfo, smi_cost_attrs);
			return -1;
		}
		if (!force_metric_only)
			stat_config.metric_only = true;

		parse_events_error__init(&errinfo);
		err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
		if (err) {
			parse_events_error__print(&errinfo, smi_cost_attrs);
			fprintf(stderr, "Cannot set up SMI cost events\n");
			return -1;
		}
		return 0;
		parse_events_error__exit(&errinfo);
		return err ? -1 : 0;
	}

	if (topdown_run) {
@@ -1875,18 +1875,22 @@ static int add_default_attributes(void)
			return -1;
		}
		if (topdown_attrs[0] && str) {
			struct parse_events_error errinfo;
			if (warn)
				arch_topdown_group_warn();
setup_metrics:
			parse_events_error__init(&errinfo);
			err = parse_events(evsel_list, str, &errinfo);
			if (err) {
				fprintf(stderr,
					"Cannot set up top down events %s: %d\n",
					str, err);
				parse_events_error__print(&errinfo, str);
				parse_events_error__exit(&errinfo);
				free(str);
				return -1;
			}
			parse_events_error__exit(&errinfo);
		} else {
			fprintf(stderr, "System does not support topdown\n");
			return -1;
@@ -1896,6 +1900,7 @@ static int add_default_attributes(void)

	if (!evsel_list->core.nr_entries) {
		if (perf_pmu__has_hybrid()) {
			struct parse_events_error errinfo;
			const char *hybrid_str = "cycles,instructions,branches,branch-misses";

			if (target__has_cpu(&target))
@@ -1906,15 +1911,16 @@ static int add_default_attributes(void)
				return -1;
			}

			parse_events_error__init(&errinfo);
			err = parse_events(evsel_list, hybrid_str, &errinfo);
			if (err) {
				fprintf(stderr,
					"Cannot set up hybrid events %s: %d\n",
					hybrid_str, err);
				parse_events_error__print(&errinfo, hybrid_str);
				return -1;
			}
			return err;
			parse_events_error__exit(&errinfo);
			return err ? -1 : 0;
		}

		if (target__has_cpu(&target))
+7 −10
Original line number Diff line number Diff line
@@ -3063,15 +3063,11 @@ static bool evlist__add_vfs_getname(struct evlist *evlist)
	struct parse_events_error err;
	int ret;

	bzero(&err, sizeof(err));
	parse_events_error__init(&err);
	ret = parse_events(evlist, "probe:vfs_getname*", &err);
	if (ret) {
		free(err.str);
		free(err.help);
		free(err.first_str);
		free(err.first_help);
	parse_events_error__exit(&err);
	if (ret)
		return false;
	}

	evlist__for_each_entry_safe(evlist, evsel, tmp) {
		if (!strstarts(evsel__name(evsel), "probe:vfs_getname"))
@@ -4925,13 +4921,14 @@ int cmd_trace(int argc, const char **argv)
	if (trace.perfconfig_events != NULL) {
		struct parse_events_error parse_err;

		bzero(&parse_err, sizeof(parse_err));
		parse_events_error__init(&parse_err);
		err = parse_events(trace.evlist, trace.perfconfig_events, &parse_err);
		if (err) {
		if (err)
			parse_events_error__print(&parse_err, trace.perfconfig_events);
		parse_events_error__exit(&parse_err);
		if (err)
			goto out;
	}
	}

	if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
		usage_with_options_msg(trace_usage, trace_options,
+2 −1
Original line number Diff line number Diff line
@@ -115,12 +115,13 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m
		goto out_delete_evlist;
	}

	bzero(&parse_error, sizeof(parse_error));
	parse_events_error__init(&parse_error);
	/*
	 * Set backward bit, ring buffer should be writing from end. Record
	 * it in aux evlist
	 */
	err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error);
	parse_events_error__exit(&parse_error);
	if (err) {
		pr_debug("Failed to parse tracepoint event, try use root\n");
		ret = TEST_SKIP;
Loading