提交 07eafd4e 编写于 作者: I Ian Rogers 提交者: Arnaldo Carvalho de Melo

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: NIan 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.comSigned-off-by: NArnaldo Carvalho de Melo <acme@redhat.com>
上级 6c191289
...@@ -113,10 +113,11 @@ static int is_tracepoint_available(const char *str, struct evlist *evlist) ...@@ -113,10 +113,11 @@ static int is_tracepoint_available(const char *str, struct evlist *evlist)
struct parse_events_error err; struct parse_events_error err;
int ret; int ret;
bzero(&err, sizeof(err)); parse_events_error__init(&err);
ret = parse_events(evlist, str, &err); ret = parse_events(evlist, str, &err);
if (err.str) if (err.str)
parse_events_error__print(&err, "tracepoint"); parse_events_error__print(&err, "tracepoint");
parse_events_error__exit(&err);
return ret; return ret;
} }
......
...@@ -78,7 +78,7 @@ static int evlist__count_evsel_fds(struct evlist *evlist) ...@@ -78,7 +78,7 @@ static int evlist__count_evsel_fds(struct evlist *evlist)
static struct evlist *bench__create_evlist(char *evstr) 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(); struct evlist *evlist = evlist__new();
int ret; int ret;
...@@ -87,14 +87,16 @@ static struct evlist *bench__create_evlist(char *evstr) ...@@ -87,14 +87,16 @@ static struct evlist *bench__create_evlist(char *evstr)
return NULL; return NULL;
} }
parse_events_error__init(&err);
ret = parse_events(evlist, evstr, &err); ret = parse_events(evlist, evstr, &err);
if (ret) { if (ret) {
parse_events_error__print(&err, evstr); parse_events_error__print(&err, evstr);
parse_events_error__exit(&err);
pr_err("Run 'perf list' for a list of valid events\n"); pr_err("Run 'perf list' for a list of valid events\n");
ret = 1; ret = 1;
goto out_delete_evlist; goto out_delete_evlist;
} }
parse_events_error__exit(&err);
ret = evlist__create_maps(evlist, &opts.target); ret = evlist__create_maps(evlist, &opts.target);
if (ret < 0) { if (ret < 0) {
pr_err("Not enough memory to create thread/cpu maps\n"); pr_err("Not enough memory to create thread/cpu maps\n");
......
...@@ -1750,14 +1750,12 @@ static int add_default_attributes(void) ...@@ -1750,14 +1750,12 @@ static int add_default_attributes(void)
(PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) |
(PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) },
}; };
struct parse_events_error errinfo;
/* Set attrs if no event is selected and !null_run: */ /* Set attrs if no event is selected and !null_run: */
if (stat_config.null_run) if (stat_config.null_run)
return 0; return 0;
bzero(&errinfo, sizeof(errinfo));
if (transaction_run) { if (transaction_run) {
struct parse_events_error errinfo;
/* Handle -T as -M transaction. Once platform specific metrics /* Handle -T as -M transaction. Once platform specific metrics
* support has been added to the json files, all architectures * support has been added to the json files, all architectures
* will use this approach. To determine transaction support * will use this approach. To determine transaction support
...@@ -1772,6 +1770,7 @@ static int add_default_attributes(void) ...@@ -1772,6 +1770,7 @@ static int add_default_attributes(void)
&stat_config.metric_events); &stat_config.metric_events);
} }
parse_events_error__init(&errinfo);
if (pmu_have_event("cpu", "cycles-ct") && if (pmu_have_event("cpu", "cycles-ct") &&
pmu_have_event("cpu", "el-start")) pmu_have_event("cpu", "el-start"))
err = parse_events(evsel_list, transaction_attrs, err = parse_events(evsel_list, transaction_attrs,
...@@ -1783,12 +1782,13 @@ static int add_default_attributes(void) ...@@ -1783,12 +1782,13 @@ static int add_default_attributes(void)
if (err) { if (err) {
fprintf(stderr, "Cannot set up transaction events\n"); fprintf(stderr, "Cannot set up transaction events\n");
parse_events_error__print(&errinfo, transaction_attrs); parse_events_error__print(&errinfo, transaction_attrs);
return -1;
} }
return 0; parse_events_error__exit(&errinfo);
return err ? -1 : 0;
} }
if (smi_cost) { if (smi_cost) {
struct parse_events_error errinfo;
int smi; int smi;
if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) { if (sysfs__read_int(FREEZE_ON_SMI_PATH, &smi) < 0) {
...@@ -1804,23 +1804,23 @@ static int add_default_attributes(void) ...@@ -1804,23 +1804,23 @@ static int add_default_attributes(void)
smi_reset = true; smi_reset = true;
} }
if (pmu_have_event("msr", "aperf") && if (!pmu_have_event("msr", "aperf") ||
pmu_have_event("msr", "smi")) { !pmu_have_event("msr", "smi")) {
if (!force_metric_only)
stat_config.metric_only = true;
err = parse_events(evsel_list, smi_cost_attrs, &errinfo);
} else {
fprintf(stderr, "To measure SMI cost, it needs " fprintf(stderr, "To measure SMI cost, it needs "
"msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); "msr/aperf/, msr/smi/ and cpu/cycles/ support\n");
parse_events_error__print(&errinfo, smi_cost_attrs);
return -1; 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) { if (err) {
parse_events_error__print(&errinfo, smi_cost_attrs); parse_events_error__print(&errinfo, smi_cost_attrs);
fprintf(stderr, "Cannot set up SMI cost events\n"); 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) { if (topdown_run) {
...@@ -1875,18 +1875,22 @@ static int add_default_attributes(void) ...@@ -1875,18 +1875,22 @@ static int add_default_attributes(void)
return -1; return -1;
} }
if (topdown_attrs[0] && str) { if (topdown_attrs[0] && str) {
struct parse_events_error errinfo;
if (warn) if (warn)
arch_topdown_group_warn(); arch_topdown_group_warn();
setup_metrics: setup_metrics:
parse_events_error__init(&errinfo);
err = parse_events(evsel_list, str, &errinfo); err = parse_events(evsel_list, str, &errinfo);
if (err) { if (err) {
fprintf(stderr, fprintf(stderr,
"Cannot set up top down events %s: %d\n", "Cannot set up top down events %s: %d\n",
str, err); str, err);
parse_events_error__print(&errinfo, str); parse_events_error__print(&errinfo, str);
parse_events_error__exit(&errinfo);
free(str); free(str);
return -1; return -1;
} }
parse_events_error__exit(&errinfo);
} else { } else {
fprintf(stderr, "System does not support topdown\n"); fprintf(stderr, "System does not support topdown\n");
return -1; return -1;
...@@ -1896,6 +1900,7 @@ static int add_default_attributes(void) ...@@ -1896,6 +1900,7 @@ static int add_default_attributes(void)
if (!evsel_list->core.nr_entries) { if (!evsel_list->core.nr_entries) {
if (perf_pmu__has_hybrid()) { if (perf_pmu__has_hybrid()) {
struct parse_events_error errinfo;
const char *hybrid_str = "cycles,instructions,branches,branch-misses"; const char *hybrid_str = "cycles,instructions,branches,branch-misses";
if (target__has_cpu(&target)) if (target__has_cpu(&target))
...@@ -1906,15 +1911,16 @@ static int add_default_attributes(void) ...@@ -1906,15 +1911,16 @@ static int add_default_attributes(void)
return -1; return -1;
} }
parse_events_error__init(&errinfo);
err = parse_events(evsel_list, hybrid_str, &errinfo); err = parse_events(evsel_list, hybrid_str, &errinfo);
if (err) { if (err) {
fprintf(stderr, fprintf(stderr,
"Cannot set up hybrid events %s: %d\n", "Cannot set up hybrid events %s: %d\n",
hybrid_str, err); hybrid_str, err);
parse_events_error__print(&errinfo, hybrid_str); 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)) if (target__has_cpu(&target))
......
...@@ -3063,15 +3063,11 @@ static bool evlist__add_vfs_getname(struct evlist *evlist) ...@@ -3063,15 +3063,11 @@ static bool evlist__add_vfs_getname(struct evlist *evlist)
struct parse_events_error err; struct parse_events_error err;
int ret; int ret;
bzero(&err, sizeof(err)); parse_events_error__init(&err);
ret = parse_events(evlist, "probe:vfs_getname*", &err); ret = parse_events(evlist, "probe:vfs_getname*", &err);
if (ret) { parse_events_error__exit(&err);
free(err.str); if (ret)
free(err.help);
free(err.first_str);
free(err.first_help);
return false; return false;
}
evlist__for_each_entry_safe(evlist, evsel, tmp) { evlist__for_each_entry_safe(evlist, evsel, tmp) {
if (!strstarts(evsel__name(evsel), "probe:vfs_getname")) if (!strstarts(evsel__name(evsel), "probe:vfs_getname"))
...@@ -4925,12 +4921,13 @@ int cmd_trace(int argc, const char **argv) ...@@ -4925,12 +4921,13 @@ int cmd_trace(int argc, const char **argv)
if (trace.perfconfig_events != NULL) { if (trace.perfconfig_events != NULL) {
struct parse_events_error parse_err; 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); 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__print(&parse_err, trace.perfconfig_events);
parse_events_error__exit(&parse_err);
if (err)
goto out; goto out;
}
} }
if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) { if ((nr_cgroups || trace.cgroup) && !trace.opts.target.system_wide) {
......
...@@ -115,12 +115,13 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m ...@@ -115,12 +115,13 @@ int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __m
goto out_delete_evlist; 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 * Set backward bit, ring buffer should be writing from end. Record
* it in aux evlist * it in aux evlist
*/ */
err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error); err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error);
parse_events_error__exit(&parse_error);
if (err) { if (err) {
pr_debug("Failed to parse tracepoint event, try use root\n"); pr_debug("Failed to parse tracepoint event, try use root\n");
ret = TEST_SKIP; ret = TEST_SKIP;
......
...@@ -123,12 +123,13 @@ static int do_test(struct bpf_object *obj, int (*func)(void), ...@@ -123,12 +123,13 @@ static int do_test(struct bpf_object *obj, int (*func)(void),
struct parse_events_state parse_state; struct parse_events_state parse_state;
struct parse_events_error parse_error; struct parse_events_error parse_error;
bzero(&parse_error, sizeof(parse_error)); parse_events_error__init(&parse_error);
bzero(&parse_state, sizeof(parse_state)); bzero(&parse_state, sizeof(parse_state));
parse_state.error = &parse_error; parse_state.error = &parse_error;
INIT_LIST_HEAD(&parse_state.list); INIT_LIST_HEAD(&parse_state.list);
err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL); err = parse_events_load_bpf_obj(&parse_state, &parse_state.list, obj, NULL);
parse_events_error__exit(&parse_error);
if (err || list_empty(&parse_state.list)) { if (err || list_empty(&parse_state.list)) {
pr_debug("Failed to add events selected by BPF\n"); pr_debug("Failed to add events selected by BPF\n");
return TEST_FAIL; return TEST_FAIL;
......
...@@ -124,6 +124,7 @@ static int expand_group_events(void) ...@@ -124,6 +124,7 @@ static int expand_group_events(void)
evlist = evlist__new(); evlist = evlist__new();
TEST_ASSERT_VAL("failed to get evlist", evlist); TEST_ASSERT_VAL("failed to get evlist", evlist);
parse_events_error__init(&err);
ret = parse_events(evlist, event_str, &err); ret = parse_events(evlist, event_str, &err);
if (ret < 0) { if (ret < 0) {
pr_debug("failed to parse event '%s', err %d, str '%s'\n", pr_debug("failed to parse event '%s', err %d, str '%s'\n",
...@@ -135,6 +136,7 @@ static int expand_group_events(void) ...@@ -135,6 +136,7 @@ static int expand_group_events(void)
rblist__init(&metric_events); rblist__init(&metric_events);
ret = test_expand_events(evlist, &metric_events); ret = test_expand_events(evlist, &metric_events);
out: out:
parse_events_error__exit(&err);
evlist__delete(evlist); evlist__delete(evlist);
return ret; return ret;
} }
......
...@@ -2045,7 +2045,6 @@ static int test_event(struct evlist_test *e) ...@@ -2045,7 +2045,6 @@ static int test_event(struct evlist_test *e)
struct evlist *evlist; struct evlist *evlist;
int ret; int ret;
bzero(&err, sizeof(err));
if (e->valid && !e->valid()) { if (e->valid && !e->valid()) {
pr_debug("... SKIP"); pr_debug("... SKIP");
return 0; return 0;
...@@ -2055,6 +2054,7 @@ static int test_event(struct evlist_test *e) ...@@ -2055,6 +2054,7 @@ static int test_event(struct evlist_test *e)
if (evlist == NULL) if (evlist == NULL)
return -ENOMEM; return -ENOMEM;
parse_events_error__init(&err);
ret = parse_events(evlist, e->name, &err); ret = parse_events(evlist, e->name, &err);
if (ret) { if (ret) {
pr_debug("failed to parse event '%s', err %d, str '%s'\n", pr_debug("failed to parse event '%s', err %d, str '%s'\n",
...@@ -2063,7 +2063,7 @@ static int test_event(struct evlist_test *e) ...@@ -2063,7 +2063,7 @@ static int test_event(struct evlist_test *e)
} else { } else {
ret = e->check(evlist); ret = e->check(evlist);
} }
parse_events_error__exit(&err);
evlist__delete(evlist); evlist__delete(evlist);
return ret; return ret;
......
...@@ -787,9 +787,11 @@ static int check_parse_id(const char *id, struct parse_events_error *error, ...@@ -787,9 +787,11 @@ static int check_parse_id(const char *id, struct parse_events_error *error,
static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event *pe) static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event *pe)
{ {
struct parse_events_error error = { .idx = 0, }; struct parse_events_error error;
int ret;
int ret = check_parse_id(id, &error, NULL); parse_events_error__init(&error);
ret = check_parse_id(id, &error, NULL);
if (ret && same_cpu) { if (ret && same_cpu) {
pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n", pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n",
pe->metric_name, id, pe->metric_expr); pe->metric_name, id, pe->metric_expr);
...@@ -800,22 +802,18 @@ static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event ...@@ -800,22 +802,18 @@ static int check_parse_cpu(const char *id, bool same_cpu, const struct pmu_event
id, pe->metric_name, pe->metric_expr); id, pe->metric_name, pe->metric_expr);
ret = 0; ret = 0;
} }
free(error.str); parse_events_error__exit(&error);
free(error.help);
free(error.first_str);
free(error.first_help);
return ret; return ret;
} }
static int check_parse_fake(const char *id) static int check_parse_fake(const char *id)
{ {
struct parse_events_error error = { .idx = 0, }; struct parse_events_error error;
int ret = check_parse_id(id, &error, &perf_pmu__fake); int ret;
free(error.str); parse_events_error__init(&error);
free(error.help); ret = check_parse_id(id, &error, &perf_pmu__fake);
free(error.first_str); parse_events_error__exit(&error);
free(error.first_help);
return ret; return ret;
} }
......
...@@ -49,7 +49,9 @@ static int session_write_header(char *path) ...@@ -49,7 +49,9 @@ static int session_write_header(char *path)
session->evlist = evlist__new(); session->evlist = evlist__new();
TEST_ASSERT_VAL("can't get evlist", session->evlist); TEST_ASSERT_VAL("can't get evlist", session->evlist);
parse_events_error__init(&err);
parse_events(session->evlist, "cpu_core/cycles/", &err); parse_events(session->evlist, "cpu_core/cycles/", &err);
parse_events_error__exit(&err);
} }
perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY);
......
...@@ -1339,7 +1339,7 @@ static int parse_ids(struct perf_pmu *fake_pmu, struct expr_parse_ctx *ids, ...@@ -1339,7 +1339,7 @@ static int parse_ids(struct perf_pmu *fake_pmu, struct expr_parse_ctx *ids,
goto err_out; goto err_out;
} }
pr_debug("Parsing metric events '%s'\n", events.buf); pr_debug("Parsing metric events '%s'\n", events.buf);
bzero(&parse_error, sizeof(parse_error)); parse_events_error__init(&parse_error);
ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu); ret = __parse_events(parsed_evlist, events.buf, &parse_error, fake_pmu);
if (ret) { if (ret) {
parse_events_error__print(&parse_error, events.buf); parse_events_error__print(&parse_error, events.buf);
...@@ -1352,6 +1352,7 @@ static int parse_ids(struct perf_pmu *fake_pmu, struct expr_parse_ctx *ids, ...@@ -1352,6 +1352,7 @@ static int parse_ids(struct perf_pmu *fake_pmu, struct expr_parse_ctx *ids,
*out_evlist = parsed_evlist; *out_evlist = parsed_evlist;
parsed_evlist = NULL; parsed_evlist = NULL;
err_out: err_out:
parse_events_error__exit(&parse_error);
evlist__delete(parsed_evlist); evlist__delete(parsed_evlist);
strbuf_release(&events); strbuf_release(&events);
return ret; return ret;
......
...@@ -2301,6 +2301,19 @@ int __parse_events(struct evlist *evlist, const char *str, ...@@ -2301,6 +2301,19 @@ int __parse_events(struct evlist *evlist, const char *str,
return ret; return ret;
} }
void parse_events_error__init(struct parse_events_error *err)
{
bzero(err, sizeof(*err));
}
void parse_events_error__exit(struct parse_events_error *err)
{
zfree(&err->str);
zfree(&err->help);
zfree(&err->first_str);
zfree(&err->first_help);
}
void parse_events_error__handle(struct parse_events_error *err, int idx, void parse_events_error__handle(struct parse_events_error *err, int idx,
char *str, char *help) char *str, char *help)
{ {
...@@ -2405,15 +2418,11 @@ void parse_events_error__print(struct parse_events_error *err, ...@@ -2405,15 +2418,11 @@ void parse_events_error__print(struct parse_events_error *err,
return; return;
__parse_events_error__print(err->idx, err->str, err->help, event); __parse_events_error__print(err->idx, err->str, err->help, event);
zfree(&err->str);
zfree(&err->help);
if (err->num_errors > 1) { if (err->num_errors > 1) {
fputs("\nInitial error:\n", stderr); fputs("\nInitial error:\n", stderr);
__parse_events_error__print(err->first_idx, err->first_str, __parse_events_error__print(err->first_idx, err->first_str,
err->first_help, event); err->first_help, event);
zfree(&err->first_str);
zfree(&err->first_help);
} }
} }
...@@ -2426,13 +2435,14 @@ int parse_events_option(const struct option *opt, const char *str, ...@@ -2426,13 +2435,14 @@ int parse_events_option(const struct option *opt, const char *str,
struct parse_events_error err; struct parse_events_error err;
int ret; int ret;
bzero(&err, sizeof(err)); parse_events_error__init(&err);
ret = parse_events(evlist, str, &err); ret = parse_events(evlist, str, &err);
if (ret) { if (ret) {
parse_events_error__print(&err, str); parse_events_error__print(&err, str);
fprintf(stderr, "Run 'perf list' for a list of valid events\n"); fprintf(stderr, "Run 'perf list' for a list of valid events\n");
} }
parse_events_error__exit(&err);
return ret; return ret;
} }
......
...@@ -242,6 +242,8 @@ int is_valid_tracepoint(const char *event_string); ...@@ -242,6 +242,8 @@ int is_valid_tracepoint(const char *event_string);
int valid_event_mount(const char *eventfs); int valid_event_mount(const char *eventfs);
char *parse_events_formats_error_string(char *additional_terms); char *parse_events_formats_error_string(char *additional_terms);
void parse_events_error__init(struct parse_events_error *err);
void parse_events_error__exit(struct parse_events_error *err);
void parse_events_error__handle(struct parse_events_error *err, int idx, void parse_events_error__handle(struct parse_events_error *err, int idx,
char *str, char *help); char *str, char *help);
void parse_events_error__print(struct parse_events_error *err, void parse_events_error__print(struct parse_events_error *err,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册