Assignment from Fake Boolean
In the following example a boolean flag is passed across an interface.
- In the source object, flags were implemented using an enum.
- In the destination object they were implemented as a bitfield.
- The bug was hidden by the use of a C89-style typedeffed BOOL (an int)
The resulting code fails to assign the boolean flag correctly. The bug is a non-issue if C99 stdbool is used instead.
Source
include //printf
if __STDC_VERSION\\ >= 199901
include
typedef _Bool BOOL;
define FALSE false
else
/* C89 Fake bool */
typedef int BOOL;
define FALSE (0)
endif
/* Source data */
enum EFLAGS {
FLAG_NONE = 0x00,
FLAG_FOO = 0x01,
FLAG_BAR = 0x02,
FLAG_MAX
} srcFlags = FLAG_NONE;
struct SFLAGS
{
int isFoo :1;
int isBar :1;
} dstFlags = {, };
int main(void)
{
BOOL tmpBool = FALSE;
srcFlags |= FLAG_BAR; /* set BAR in src */
tmpBool = (srcFlags & FLAG_BAR); /* pass in BOOL /
/ fake BOOL: tmpBool has value 2
* C99 _Bool: tmpBool has value true
*/
dstFlags.isBar = tmpBool; /* set in dst /
/ fake BOOL: isBar is assigned (2 & 0x01) = 0 !!!
* C99 _Bool: isBar is assigned true
*/
if (dstFlags.isBar)
{
printf("dstFlags.isBar is TRUE");
}
else
{
printf("dstFlags.isBar is FALSE");
}
return ;
}
Results
$ gcc -std=c89 -pedantic -Wall -o bitfield1 bitfield1.c && ./bitfield1
dstFlags.isBar is FALSE
$ gcc -std=c99 -pedantic -Wall -o bitfield1 bitfield1.c && ./bitfield1
dstFlags.isBar is TRUE
Lesson
- Always sanitise fake BOOL with !!(x) or (x != 0)
- Or avoid the problem entirely by using C99 _Bool