Fixing the dynamic array format field parsing.

Currently the event_read_fields function could segfault while parsing
dynamic array other than string type. The reason is the event->pevent
does not need to be set and gets dereferenced unconditionaly.

Also adding proper initialization of field->elementsize based on the
parsed dynamic type.

Signed-off-by: Jiri Olsa <jo...@redhat.com>
Cc: Arnaldo Carvalho de Melo <a...@redhat.com>
Cc: Steven Rostedt <rost...@goodmis.org>
Cc: Corey Ashford <cjash...@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweis...@gmail.com>
Cc: Ingo Molnar <mi...@elte.hu>
Cc: Namhyung Kim <namhy...@kernel.org>
Cc: Paul Mackerras <pau...@samba.org>
Cc: Peter Zijlstra <a.p.zijls...@chello.nl>
---
 tools/lib/traceevent/event-parse.c | 40 +++++++++++++++++++++++++++++++++++---
 tools/lib/traceevent/event-parse.h |  1 +
 2 files changed, 38 insertions(+), 3 deletions(-)

diff --git a/tools/lib/traceevent/event-parse.c 
b/tools/lib/traceevent/event-parse.c
index f504619..d682df2 100644
--- a/tools/lib/traceevent/event-parse.c
+++ b/tools/lib/traceevent/event-parse.c
@@ -1223,6 +1223,34 @@ static int field_is_long(struct format_field *field)
        return 0;
 }
 
+static unsigned int field_dynamic_elem_size(struct format_field *field)
+{
+       /* This covers all FIELD_IS_STRING types. */
+       static struct {
+               char *type;
+               unsigned int size;
+       } table[] = {
+               { "u8",   1 },
+               { "u16",  2 },
+               { "u32",  4 },
+               { "u64",  8 },
+               { "s8",   1 },
+               { "s16",  2 },
+               { "s32",  4 },
+               { "s64",  8 },
+               { "char", 1 },
+               { },
+       };
+       int i;
+
+       for (i = 0; table[i].type; i++) {
+               if (!strcmp(table[i].type, field->type_dyn))
+                       return table[i].size;
+       }
+
+       return 0;
+}
+
 static int event_read_fields(struct event_format *event, struct format_field 
**fields)
 {
        struct format_field *field = NULL;
@@ -1390,7 +1418,7 @@ static int event_read_fields(struct event_format *event, 
struct format_field **f
                                field->type = new_type;
                                strcat(field->type, " ");
                                strcat(field->type, field->name);
-                               free_token(field->name);
+                               field->type_dyn = field->name;
                                strcat(field->type, brackets);
                                field->name = token;
                                type = read_token(&token);
@@ -1477,10 +1505,14 @@ static int event_read_fields(struct event_format 
*event, struct format_field **f
                if (field->flags & FIELD_IS_ARRAY) {
                        if (field->arraylen)
                                field->elementsize = field->size / 
field->arraylen;
+                       else if (field->flags & FIELD_IS_DYNAMIC)
+                               field->elementsize = 
field_dynamic_elem_size(field);
                        else if (field->flags & FIELD_IS_STRING)
                                field->elementsize = 1;
-                       else
-                               field->elementsize = event->pevent->long_size;
+                       else if (field->flags & FIELD_IS_LONG)
+                               field->elementsize = event->pevent ?
+                                                    event->pevent->long_size :
+                                                    sizeof(long);
                } else
                        field->elementsize = field->size;
 
@@ -1496,6 +1528,7 @@ fail:
 fail_expect:
        if (field) {
                free(field->type);
+               free(field->type_dyn);
                free(field->name);
                free(field);
        }
@@ -5500,6 +5533,7 @@ static void free_format_fields(struct format_field *field)
        while (field) {
                next = field->next;
                free(field->type);
+               free(field->type_dyn);
                free(field->name);
                free(field);
                field = next;
diff --git a/tools/lib/traceevent/event-parse.h 
b/tools/lib/traceevent/event-parse.h
index 7be7e89..4d54af2 100644
--- a/tools/lib/traceevent/event-parse.h
+++ b/tools/lib/traceevent/event-parse.h
@@ -174,6 +174,7 @@ struct format_field {
        struct format_field     *next;
        struct event_format     *event;
        char                    *type;
+       char                    *type_dyn;
        char                    *name;
        int                     offset;
        int                     size;
-- 
1.7.11.7

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to