Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Catch incorrect usage of c bool

Tags:

In a C project (OpenVPN is the project in question, commit 4029971240b6274b9b30e76ff74c7f689d7d9750) we had a emulation of bool

typedef int bool;
#define false 0
#define true 1

and now switch to C99 bool

#include <stdbool.h>

But in the project there is somewhere a bad usage of the bool. I know that the std bool behaves different. E.g.

bool t;

t=2;
if ( t == true)
    printf("True!\n");
else
    printf("False!\n");

Will return True! with stdbool.h and False! with the #define emulation.

My question Is there a way to find these code parts that behave different with stdbool and the emulated bool? Perhaps some compiler flag I overlooked or a good llvm or gcc intermediate format that can be diffed?

It is nothing as simple as in the example above but must be something that not as easy to see. Definitively not a == true.

UPDATE: We found the issue (mbuf_set has an int member len). It kind of stupid but the question still remains how to catch these. I am surprised the integer overflow checks don't catch things like this:

 static inline bool
 mbuf_len (const struct mbuf_set *ms)
 {
   return ms->len;
 }
like image 963
plaisthos Avatar asked Mar 11 '13 12:03

plaisthos


1 Answers

The kind of usage you're describing is correct, well defined behaviour. So the compiler will not produce any warnings. One possible way around this is to change the typedef:

typedef enum {false, true} bool;

This will still allow the code to compile without error (as it's well defined), but you may be able to force warnings from a compiler or analyser. For example, clang will pick this kind of thing up with -Weverything:

$ clang -o a a.c -Weverything
a.c:7:11: warning: integer constant not in range of enumerated type 'bool'
      [-Wassign-enum]
        bool n = 2;

Of course this will not do any runtime checking. It will still allow the typedef bool variable to be changed to something other than 0 or 1 (e.g. via a function call or in an expression). The only way to detect those instances is to use a debugger.

The macros for true and false in stdbool.h are designed really only for the _Bool type. This is because this type can only hold the values 0 and 1; any value you assign that isn't 0 is stored as 1. So for a boolean type only, the true and false macros are guaranteed to work.

Without the _Bool type, there's no way to have the language itself do this for you directly, because there's no comparable type, and you'd effectively be asking it to allow that 2 == 1 returns true.

There are a few ways to implement the same behaviour, e.g. using a macro such as BOOL(n) in every instance of using the variable n, to ensure its value is 0 or 1 only. This way, you'd get the same result whether using _Bool or an int for n. For example:

#define BOOL(n) ((n) != 0 ? 1 : 0 )

bool b = rand() % 100;

if (BOOL(b) == true) ...

This would work whether using stdbool or a typedef.

like image 174
teppic Avatar answered Oct 19 '22 18:10

teppic