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 <stdio.h> //printf
#if __STDC_VERSION__ >= 199901
# include <stdbool.h>
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 = {0, 0};
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 0;
}
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