# V560. Part of conditional expression is always true/false.

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

Рассмотрим пример:

    #define REO_INPLACEACTIVE (0x02000000L)
    ...
    if (reObj.dwFlags && REO_INPLACEACTIVE)
      m_pRichEditOle->InPlaceDeactivate();

Программист хотел проверить состояние определенного бита в переменной dwFlags. Но из-за опечатки он написал оператор '&&', вместо оператора '&'. Корректный код:

    if (reObj.dwFlags & REO_INPLACEACTIVE)
      m_pRichEditOle->InPlaceDeactivate();

Рассмотрим другой пример:

    if (a = 10 || a == 20)

Случайно вместо оператора сравнения '==' написан оператор присваивания '='. С точки зрения языка Си++, это выражение будет идентично выражению вида "if (a = (10 || a == 20))".

Выражение "10 || a == 20" анализатор считает опасным, так как левая его часть представляет собой константу. Корректный код:

    if (a == 10 || a == 20)

Иногда предупреждение V560 выявляет не ошибку, а просто избыточный код. Рассмотрим пример:

    if (!mainmenu) {
      if (freeze || winfreeze ||
          (mainmenu && gameon) ||
          (!gameon && gamestarted))
        drawmode = normalmode;
    }

Анализатор предупредит, что в подвыражении (mainmenu && gameon) переменная mainmenu всегда равна 0. То, что переменная mainmenu равна нулю, следует из вышестоящей проверки " if (!mainmenu)". Этот код может быть вполне корректен. Однако он избыточен, и лучше его упростить. Это сделает программу более простой для понимания другими разработчиками.

Упрощенный вариант кода:

    if (!mainmenu) {
      if (freeze || winfreeze ||
          (!gameon && gamestarted))
        drawmode = normalmode;
    }

Рассмотрим более интересный случай.

    int16u Integer = ReadInt16u(Liste);
    int32u Exponent=(Integer>>10) & 0xFF;
    if (Exponent==0 || Exponent==0xFF)  // V560
      return 0;

Пользователь, приславший этот пример, был озадачен, почему анализатор выдаёт предупреждение, в котором утверждается, что подвыражение 'Exponent==0xFF' всегда ложное. Давайте разберемся. Для этого нам надо внимательно посчитать.

16-битная беззнаковая переменная 'Integer' имеет диапазон возможных значений [0..0b1111111111111111] или [0..0xFFFF].

При сдвиге вправо на 10 бит, диапазон возможных значений уменьшается: [0..0b111111] или [0..0x3F].

Далее выполняется операция '& 0xFF'.

В результате, никак невозможно получить значение '0xFF'. Максимум, это будет '0x3F'.

Ряд конструкций на языке Си++ анализатор считает безопасными, даже если в них часть выражения представляется константой. Примеры некоторых ситуаций, когда анализатор не считает код опасными:

- подвыражение содержит операторы sizeof(): if (a == b && sizeof(T) < sizeof(__int64)) {};
- выражение находится в макросе: assert(false);
- сравниваются две числовых константы: if (MY_DEFINE_BITS_COUNT == 4) {};
- и так далее.

Особые настройки диагностики V560

По дополнительной просьбе пользователей появилась возможность управлять поведением диагностики V560. В общем заголовочном файле или pvsconfig-файле можно написать комментарий специального вида:

    //+V560 ENABLE_PEDANTIC_WARNINGS

Режим 'ENABLE_PEDANTIC_WARNINGS' ослабляет исключения диагностики. Рассмотрим пример:

    void foo()
    {
      bool debugCheck = false; // maybe in macros
      if (x)
      {
        if (debugCheck)
        {
          ....
        }
      }
    }

По умолчанию анализатор не будет считать такой код опасным, так как часто он пишется для отладки. Комментарий позволит ослабить исключение диагностики, чтобы анализатор мог сообщить о проблеме.

Данная диагностика классифицируется как:

CWE-570 CWE-571

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V560.