Main Content

Possible invalid operation on boolean operand

Operation can exceed precision of Boolean operand or result in arbitrary value

Description

This defect occurs when you use a Boolean operand in an arithmetic, relational, or bitwise operation and:

  • The Boolean operand has a trap representation. The size of a Boolean type in memory is at least one addressable unit (size of char). A Boolean type requires only one bit to represent the value true (1) or false (0). The representation of a Boolean operand in memory contains padding bits. The memory representation can result in values that are not true or false, a trap representation.

  • The result of the operation can exceed the precision of the Boolean operand.

For example, in this code snippet:

bool_v >> 2

  • If the value of bool_v is true (1) or false (0), the bitwise shift exceeds the one-bit precision of bool_v and always results in 0.

  • If bool_v has a trap representation, the result of the operation is an arbitrary value.

Possible invalid operation on boolean operand raises no defect when:

  • The operation does not result in a precision overflow. For instance, bitwise & or | operations with 0x01 or 0x00.

  • The Boolean operand cannot have a trap representation. For instance, a constant expression that results in 0 or 1, or a comparison evaluated to true or false.

Risk

Arithmetic, relational, or bitwise operations on a Boolean operand can exceed the operand precision and cause unexpected results when used as a Boolean value. Operations on Boolean operands with trap representations can return arbitrary values.

Fix

Avoid performing operations on Boolean operands other than these operations:

  • Assignment operation (=).

  • Equality operations (== or !=).

  • Logical operations (&&, ||, or !).

Examples

expand all

#include <stdio.h>
#include <stdbool.h>

#define BOOL _Bool

int arr[2] = {1, 2};

int func(BOOL b)
{
    return arr[b];
}

int main(void)
{
    BOOL b;
    char* ptr = (char*)&b;
    *ptr = 64;
    return func(b);
}

In this example, Boolean operand b is used as an array index in func for an array with two elements. Depending on the compiler and optimization flags you use, the value b might not be 0 or 1. For instance, in Linux® Debian 8, if you use gcc version 4.9 with optimization flag -O0, the value of b is 64, which causes a buffer overflow.

Correction — Use Only Last Significant Bit Value of Boolean Operand

One possible correction is to use a variable b0 of type unsigned int to get only the value of the last significant bit of the Boolean operand. The value of this bit is in the range [0..1], even if the Boolean operand has a trap representation.

#include <stdio.h>
#include <stdbool.h>

#define BOOL _Bool

int arr[2] = {1, 2};

int func(BOOL b)
{
    unsigned int b0 = (unsigned int)b;
    b0 &= 0x1;
    return arr[b0];
}

int main(void)
{
    BOOL b;
    char* ptr = (char*)&b;
    *ptr = 64;
    return func(b);
} 

Note that a trap representation is often the result of an earlier issue in the code, such as:

  • A non-initialized variable of bool type.

  • A side effect that modifies any part of a bool type object using a lvalue expression.

  • A read of a bool member from a union type with the last stored value of another type.

As such, it is best practice to respect boolean semantics even in C++ code.

#include <iostream>

template <typename T>
bool less_or_equal(const T& x, const T& y)
{
    std::cout << "INTEGER VERSION" << '\n';
    return x <= y;
}
bool b1 = true, b2 = false;
int i1 = 2, i2 = 3;

int main()
{
    std::cout << std::boolalpha;
    std::cout << "less_or_equal(" << b1 << ',' << b2 << ") = " << less_or_equal<bool>(b1, b2) << '\n';
    std::cout << "less_or_equal(" << i1 << ',' << i2 << ") = " << less_or_equal<int>(11, 12) << '\n';
    return 0;
}

In this example, function template less_or_equal evaluates whether variable x is less than or equal to y. When you pass boolean types to this function, the <= operation might result in an arbitrary value if the memory representation of the operands, including their padding bits, is neither 1 nor 0.

Correction — Specialize Function Template for Boolean Types

One possible correction is to specialize the function template for boolean types. The specialized function template uses a logical (||) operation to compare the boolean operands.

#include <iostream>

template <typename T>
bool less_or_equal(const T& x, const T& y)
{
    std::cout << "INTEGER VERSION" << '\n';
    return x <= y;
}

template<>
bool less_or_equal<bool>(const bool& x, const bool& y)
{
    std::cout << "BOOLEAN VERSION" << '\n';
    return !x || y;
}

bool b1 = true, b2 = false;
int i1 = 2, i2 = 3;

int main()
{
    std::cout << std::boolalpha;
    std::cout << "less_or_equal(" << b1 << ',' << b2 << ") = " << less_or_equal<bool>(b1, b2) << '\n';
    std::cout << "less_or_equal(" << i1 << ',' << i2 << ") = " << less_or_equal<int>(11, 12) << '\n';
    return 0;
}

Result Information

Group: Numerical
Language: C | C++
Default: Off
Command-Line Syntax: INVALID_OPERATION_ON_BOOLEAN
Impact: Low

Version History

Introduced in R2018b