perf parse: Ensure config and str in terms are unique
Make it easier to release memory associated with parse event terms by duplicating the string for the config name and ensuring the val string is a duplicate. Currently the parser may memory leak terms and this is addressed in a later patch. 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/20191030223448.12930-6-irogers@google.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
448d732cef
commit
b6645a7235
|
@ -1412,7 +1412,6 @@ int parse_events_add_pmu(struct parse_events_state *parse_state,
|
|||
int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
|
||||
char *str, struct list_head **listp)
|
||||
{
|
||||
struct list_head *head;
|
||||
struct parse_events_term *term;
|
||||
struct list_head *list;
|
||||
struct perf_pmu *pmu = NULL;
|
||||
|
@ -1429,19 +1428,30 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
|
|||
|
||||
list_for_each_entry(alias, &pmu->aliases, list) {
|
||||
if (!strcasecmp(alias->name, str)) {
|
||||
struct list_head *head;
|
||||
char *config;
|
||||
|
||||
head = malloc(sizeof(struct list_head));
|
||||
if (!head)
|
||||
return -1;
|
||||
INIT_LIST_HEAD(head);
|
||||
if (parse_events_term__num(&term, PARSE_EVENTS__TERM_TYPE_USER,
|
||||
str, 1, false, &str, NULL) < 0)
|
||||
config = strdup(str);
|
||||
if (!config)
|
||||
return -1;
|
||||
if (parse_events_term__num(&term,
|
||||
PARSE_EVENTS__TERM_TYPE_USER,
|
||||
config, 1, false, &config,
|
||||
NULL) < 0) {
|
||||
free(list);
|
||||
free(config);
|
||||
return -1;
|
||||
}
|
||||
list_add_tail(&term->list, head);
|
||||
|
||||
if (!parse_events_add_pmu(parse_state, list,
|
||||
pmu->name, head,
|
||||
true, true)) {
|
||||
pr_debug("%s -> %s/%s/\n", str,
|
||||
pr_debug("%s -> %s/%s/\n", config,
|
||||
pmu->name, alias->str);
|
||||
ok++;
|
||||
}
|
||||
|
@ -1450,8 +1460,10 @@ int parse_events_multi_pmu_add(struct parse_events_state *parse_state,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (!ok)
|
||||
if (!ok) {
|
||||
free(list);
|
||||
return -1;
|
||||
}
|
||||
*listp = list;
|
||||
return 0;
|
||||
}
|
||||
|
@ -2746,30 +2758,51 @@ int parse_events_term__sym_hw(struct parse_events_term **term,
|
|||
char *config, unsigned idx)
|
||||
{
|
||||
struct event_symbol *sym;
|
||||
char *str;
|
||||
struct parse_events_term temp = {
|
||||
.type_val = PARSE_EVENTS__TERM_TYPE_STR,
|
||||
.type_term = PARSE_EVENTS__TERM_TYPE_USER,
|
||||
.config = config ?: (char *) "event",
|
||||
.config = config,
|
||||
};
|
||||
|
||||
if (!temp.config) {
|
||||
temp.config = strdup("event");
|
||||
if (!temp.config)
|
||||
return -ENOMEM;
|
||||
}
|
||||
BUG_ON(idx >= PERF_COUNT_HW_MAX);
|
||||
sym = &event_symbols_hw[idx];
|
||||
|
||||
return new_term(term, &temp, (char *) sym->symbol, 0);
|
||||
str = strdup(sym->symbol);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
return new_term(term, &temp, str, 0);
|
||||
}
|
||||
|
||||
int parse_events_term__clone(struct parse_events_term **new,
|
||||
struct parse_events_term *term)
|
||||
{
|
||||
char *str;
|
||||
struct parse_events_term temp = {
|
||||
.type_val = term->type_val,
|
||||
.type_term = term->type_term,
|
||||
.config = term->config,
|
||||
.config = NULL,
|
||||
.err_term = term->err_term,
|
||||
.err_val = term->err_val,
|
||||
};
|
||||
|
||||
return new_term(new, &temp, term->val.str, term->val.num);
|
||||
if (term->config) {
|
||||
temp.config = strdup(term->config);
|
||||
if (!temp.config)
|
||||
return -ENOMEM;
|
||||
}
|
||||
if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM)
|
||||
return new_term(new, &temp, NULL, term->val.num);
|
||||
|
||||
str = strdup(term->val.str);
|
||||
if (!str)
|
||||
return -ENOMEM;
|
||||
return new_term(new, &temp, str, 0);
|
||||
}
|
||||
|
||||
int parse_events_copy_term_list(struct list_head *old,
|
||||
|
|
|
@ -665,9 +665,11 @@ PE_NAME array '=' PE_VALUE
|
|||
PE_DRV_CFG_TERM
|
||||
{
|
||||
struct parse_events_term *term;
|
||||
char *config = strdup($1);
|
||||
|
||||
ABORT_ON(!config);
|
||||
ABORT_ON(parse_events_term__str(&term, PARSE_EVENTS__TERM_TYPE_DRV_CFG,
|
||||
$1, $1, &@1, NULL));
|
||||
config, $1, &@1, NULL));
|
||||
$$ = term;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue