genksyms: Duplicate function pointer type definitions segfault
authorRichard Yao <richard.yao@clusterhq.com>
Mon, 20 Jul 2015 23:52:48 +0000 (19:52 -0400)
committerMichal Marek <mmarek@suse.com>
Thu, 20 Aug 2015 12:55:55 +0000 (14:55 +0200)
I noticed that genksyms will segfault when it sees duplicate function
pointer type declaration when I placed the same function pointer
definition in two separate headers in a local branch as an intermediate
step of some refactoring. This can be reproduced by piping the following
minimal test case into `genksyms -r /dev/null` or alternatively, putting
it into a C file attempting a build:

typedef int (*f)();
typedef int (*f)();

Attaching gdb to genksyms to understand this failure is useless without
changing CFLAGS to emit debuginfo. Once you have debuginfo, you will
find that the failure is that `char *s` was NULL and the program
executed `while(*s)`. At which point, further debugging requires
familiarity with compiler front end / parser development.

What happens is that flex identifies the first instance of the token "f"
as IDENT and the yacc parser adds it to the symbol table. On the second
instance, flex will identify "f" as TYPE, which triggers an error case
in the yacc parser. Given that TYPE would have been IDENT had it not
been in the symbol table, the the segmentaion fault could be avoided by
treating TYPE as IDENT in the affected rule.

Some might consider placing identical function pointer type declarations
in different headers to be poor style might consider a failure to be
beneficial. However, failing through a segmentation fault makes the
cause non-obvious and can waste the time of anyone who encounters it.

Signed-off-by: Richard Yao <richard.yao@clusterhq.com>
Acked-by: Madhuri Yechuri <madhuriyechuri@clusterhq.com>
Signed-off-by: Michal Marek <mmarek@suse.com>
scripts/genksyms/parse.y

index b9f4cf202302d46d71e3899fc49f565371975c83..723ab30fe9d46951b6106c38bc81b1460c5df342 100644 (file)
@@ -303,6 +303,15 @@ direct_declarator:
                    $$ = $1;
                  }
                }
+       | TYPE
+               { if (current_name != NULL) {
+                   error_with_pos("unexpected second declaration name");
+                   YYERROR;
+                 } else {
+                   current_name = (*$1)->string;
+                   $$ = $1;
+                 }
+               }
        | direct_declarator '(' parameter_declaration_clause ')'
                { $$ = $4; }
        | direct_declarator '(' error ')'