exponenta event banner

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

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

Описание

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

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

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

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

bool_v >> 2

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

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

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

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

  • Логический операнд не может иметь представление ловушки. Например, постоянное выражение, которое приводит к 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], даже если логический операнд имеет представление ловушки.

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

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

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

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

  • Чтение логического элемента из типа объединения с последним сохраненным значением другого типа.

Поэтому рекомендуется уважать булеву семантику даже в коде C++.

#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++
По умолчанию: Откл.
Синтаксис командной строки: INVALID_OPERATION_ON_BOOLEAN
Воздействие: Низкий
ИДЕНТИФИКАТОР CWE : 190
Представлен в R2018b