perf probe: Release all dynamically allocated parameters
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Thu, 16 Jan 2014 09:39:47 +0000 (09:39 +0000)
committerArnaldo Carvalho de Melo <acme@redhat.com>
Thu, 16 Jan 2014 19:29:02 +0000 (16:29 -0300)
To fix a memory leak, release all dynamically allocated
options/parameters in params data structure. This also
introduces/exports some init/clear routines.

Reported-by: David Ahern <dsahern@gmail.com>
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: "David A. Long" <dave.long@linaro.org>
Cc: "Steven Rostedt (Red Hat)" <rostedt@goodmis.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20140116093947.24403.80118.stgit@kbuild-fedora.novalocal
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
tools/perf/builtin-probe.c
tools/perf/util/probe-event.c
tools/perf/util/probe-event.h

index 43ff33d0007b1edbe9e9db1ea37e6c6c1bfefbfb..78948882e3de72c9a521f1d3c6d3bff29f2e493d 100644 (file)
@@ -59,7 +59,7 @@ static struct {
        struct perf_probe_event events[MAX_PROBES];
        struct strlist *dellist;
        struct line_range line_range;
-       const char *target;
+       char *target;
        int max_probe_points;
        struct strfilter *filter;
 } params;
@@ -98,7 +98,10 @@ static int set_target(const char *ptr)
         * short module name.
         */
        if (!params.target && ptr && *ptr == '/') {
-               params.target = ptr;
+               params.target = strdup(ptr);
+               if (!params.target)
+                       return -ENOMEM;
+
                found = 1;
                buf = ptr + (strlen(ptr) - 3);
 
@@ -116,6 +119,9 @@ static int parse_probe_event_argv(int argc, const char **argv)
        char *buf;
 
        found_target = set_target(argv[0]);
+       if (found_target < 0)
+               return found_target;
+
        if (found_target && argc == 1)
                return 0;
 
@@ -217,7 +223,6 @@ static int opt_show_lines(const struct option *opt __maybe_unused,
 
        params.show_lines = true;
        ret = parse_line_range_desc(str, &params.line_range);
-       INIT_LIST_HEAD(&params.line_range.line_list);
 
        return ret;
 }
@@ -263,7 +268,28 @@ static int opt_set_filter(const struct option *opt __maybe_unused,
        return 0;
 }
 
-int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
+static void init_params(void)
+{
+       line_range__init(&params.line_range);
+}
+
+static void cleanup_params(void)
+{
+       int i;
+
+       for (i = 0; i < params.nevents; i++)
+               clear_perf_probe_event(params.events + i);
+       if (params.dellist)
+               strlist__delete(params.dellist);
+       line_range__clear(&params.line_range);
+       free(params.target);
+       if (params.filter)
+               strfilter__delete(params.filter);
+       memset(&params, 0, sizeof(params));
+}
+
+static int
+__cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 {
        const char * const probe_usage[] = {
                "perf probe [<options>] 'PROBEDEF' ['PROBEDEF' ...]",
@@ -417,6 +443,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                ret = show_available_funcs(params.target, params.filter,
                                        params.uprobes);
                strfilter__delete(params.filter);
+               params.filter = NULL;
                if (ret < 0)
                        pr_err("  Error: Failed to show functions."
                               " (%d)\n", ret);
@@ -456,6 +483,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
                                          params.filter,
                                          params.show_ext_vars);
                strfilter__delete(params.filter);
+               params.filter = NULL;
                if (ret < 0)
                        pr_err("  Error: Failed to show vars. (%d)\n", ret);
                return ret;
@@ -464,7 +492,6 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
 
        if (params.dellist) {
                ret = del_perf_probe_events(params.dellist);
-               strlist__delete(params.dellist);
                if (ret < 0) {
                        pr_err("  Error: Failed to delete events. (%d)\n", ret);
                        return ret;
@@ -483,3 +510,14 @@ int cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
        }
        return 0;
 }
+
+int cmd_probe(int argc, const char **argv, const char *prefix)
+{
+       int ret;
+
+       init_params();
+       ret = __cmd_probe(argc, argv, prefix);
+       cleanup_params();
+
+       return ret;
+}
index 579b655c0f9300a4dd7b522e536f531d05fb45ce..c68711c50f47d1760eae2200a53c3da258c54706 100644 (file)
@@ -794,6 +794,28 @@ int show_available_vars(struct perf_probe_event *pevs __maybe_unused,
 }
 #endif
 
+void line_range__clear(struct line_range *lr)
+{
+       struct line_node *ln;
+
+       free(lr->function);
+       free(lr->file);
+       free(lr->path);
+       free(lr->comp_dir);
+       while (!list_empty(&lr->line_list)) {
+               ln = list_first_entry(&lr->line_list, struct line_node, list);
+               list_del(&ln->list);
+               free(ln);
+       }
+       memset(lr, 0, sizeof(*lr));
+}
+
+void line_range__init(struct line_range *lr)
+{
+       memset(lr, 0, sizeof(*lr));
+       INIT_LIST_HEAD(&lr->line_list);
+}
+
 static int parse_line_num(char **ptr, int *val, const char *what)
 {
        const char *start = *ptr;
index d481c46e079677c149c0a125333c3b978208bd87..fcaf7273e85a35f41ac465c2f343ec07cbd0f1a4 100644 (file)
@@ -120,6 +120,12 @@ extern void clear_perf_probe_event(struct perf_probe_event *pev);
 /* Command string to line-range */
 extern int parse_line_range_desc(const char *cmd, struct line_range *lr);
 
+/* Release line range members */
+extern void line_range__clear(struct line_range *lr);
+
+/* Initialize line range */
+extern void line_range__init(struct line_range *lr);
+
 /* Internal use: Return kernel/module path */
 extern const char *kernel_get_module_path(const char *module);