Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Finding "fallthroughs" in C code

There were several nasty bugs discovered in a product I am working on, all related to inadvertent "fall throughs" in switch statements.

Now, I would like to go one step beyond - I would like to detect switch statement fall throughs in a large body of C code. I can use only Linux and gcc 5.6 for compilation (so no clang or newer gcc; this is because newer gcc does not exist for the target architecture for our project).

This is a code without fall through:

    switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something
            break;
        case 2:
        case 3:
        case 4:
            // Do something
            break;
   }

This is a code with fall throughs:

   switch(m_loadAnimSubCt){
        case 0: 
        case 1: 
            // Do something but fall through to the other cases 
            // after doing it.
        case 2:
        case 3:
        case 4:
            // Do something else.
            break;
   }
like image 802
VividD Avatar asked Sep 01 '17 11:09

VividD


2 Answers

If you are using GCC, you should use the Wimplicit-fallthrough compiler option to generate a warning for fallthroughs. You can alternatively make it into an error using -Werror (i.e. -Werror=implicit-fallthrough for this specific warning.

I would prefer using -Wextra (which includes this and many other additional warnings), but if this is some large legacy codebase, it might generate too much noise. It is what you should strive for, to pass the build with -Wextra -Wpedantic -Werror.

If your compiler version doesn't support such option, perhaps you can write your own regex which would match all cases not prefixed by a previous case statement, although you would have to be careful to ensure that the regex matches all occurrences, regardless of formatting/comments.

For example, you could use something like this (here is a demo):

(?# match any 'case' following 'break;', ':' or '{' into a non-capturing group)
(?# then match the remaining 'case' into a named "fallthrough" group)
(?:(break;|:|{)[\r\n\s]*case) | (?<fallthrough>case)

So you can run a perl (or python, or whatever) script against your folder and dump all lines where the "fallthrough" group is captured.

like image 74
Groo Avatar answered Oct 26 '22 22:10

Groo


I would suggest compiling your code with a newer compiler just to detect those (I know you mentioned you could not do that for the project but it's sometimes useful to compile it with something else to have a different perspective on things).

What we have at my work is an (scarily) old version of GCC compiling our "official" code and clang doing a dummy compilation just to have better static analysis.

like image 42
Alex Garcia Avatar answered Oct 27 '22 00:10

Alex Garcia