Possible invalid operation on boolean operand

Операция может превысить точность логического операнда или привести к произвольному значению

Описание

Этот дефект возникает, когда вы используете логический операнд в арифметической, реляционной или побитовой операции и:

  • Логический операнд имеет представление trap. Размер логического типа в памяти составляет по крайней мере один адресуемый модуль (размер char). Логический тип требует только одного бита, чтобы представлять значение true (1) или false (0). Представление логического операнда в памяти содержит биты заполнения. Представление памяти может привести к значениям, которые не true или false, представление ловушки.

  • Результат операции может превысить точность логического операнда.

Для примера, в этом фрагменте кода:

bool_v >> 2

  • Если значение bool_v является true (1) или false (0), битовый сдвиг превышает однобитовую точность bool_v и всегда приводит к 0.

  • Если bool_v имеет представление trap, результатом операции является произвольное значение.

Возможная недопустимая операция с логическим операндом не вызывает дефекта, когда:

  • Операция не приводит к переполнению точности. Для образца, побитовых & или | операции с 0x01 или 0x00.

  • Логический операнд не может иметь представление trap. Для образца - постоянное выражение, которое приводит к 0 или 1, или сравнение, рассчитанное как true или false.

Риск

Арифметические, реляционные или побитовые операции над булевым операндом могут превысить точность операнда и вызвать неожиданные результаты при использовании в качестве логического значения. Операции над логическими операндами с представлениями trap могут вернуть произвольные значения.

Зафиксировать

Избегайте выполнения операций с логическими операндами, отличными от этих операций:

  • Операция назначения (=).

  • Операции по обеспечению равенства (== или !=).

  • Логические операции (&&, ||, или !).

Примеры

расширить все

#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);
}

В этом примере логический операнд b используется как индекс массива в func для массива с двумя элементами. В зависимости от используемого компилятора и флагов оптимизации, значение b может не быть 0 или 1. Например, в Linux® Debian 8, если вы используете gcc версия 4.9 с флагом оптимизации -O0, значение b равен 64, что вызывает переполнение буфера.

Коррекция - используйте только последнее значимое битовое значение логического операнда

Одной из возможных коррекций является использование переменной b0 типа unsigned int получить только значение последнего значимого бита логического операнда. Значение этого бита находится в области значений [0..1], даже если логический операнд имеет представление trap.

#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);
} 

Обратите внимание, что представление trap часто является результатом более ранней проблемы в коде, такой как:

  • Неинициализированная переменная типа bool.

  • Побочный эффект, который изменяет любую часть объекта типа bool с помощью выражения lvalue.

  • Чтение представителя bool из типа union с последним сохраненным значением другого типа.

Поэтому лучше всего уважать логическую семантику даже в коде С++.

#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;
}

В этом примере шаблон функции less_or_equal определяет, является ли переменная x меньше или равной y. Когда вы передаете логические типы этой функции, <= операция может привести к произвольному значению, если представление памяти операндов, включая их биты заполнения, не является ни 1, ни 0.

Коррекция - Специализированный шаблон функции для булевых типов

Одной из возможных коррекций является специализация шаблона функции для булевых типов. Специализированный шаблон функции использует логический (||) операция для сравнения логических операндов.

#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;
}

Информация о результатах

Группа: Численный
Язык: C | C++
По умолчанию: Off
Синтаксис командной строки : INVALID_OPERATION_ON_BOOLEAN
Влияние: Низкое
ИДЕНТИФИКАТОР CWE : 190
Введенный в R2018b