# V501. Identical sub-expressions to the left and to the right of 'foo' operator.

Анализатор обнаружил фрагмент кода, который, скорее всего, содержит логическую ошибку. В тексте программы имеется оператор (<, >, <=, >=, ==, !=, &&, ||, -, /), слева и справа от которого расположены одинаковые подвыражения.

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

    if (a.x != 0 && a.x != 0)

В данном случае оператор '&&' окружен одинаковыми подвыражениями "a.x != 0", что позволяет обнаружить ошибку, допущенную по невнимательности. Корректный код, который не вызовет подозрений у анализатора, будет выглядеть так:

    if (a.x != 0 && a.y != 0)

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

    class Foo {
      int iChilds[2];
      ...
      bool hasChilds() const { return(iChilds > 0 || iChilds > 0); }
      ...
    }

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

    bool hasChilds() const { return(iChilds[0] > 0 || iChilds[1] > 0);}

Анализатор выдает предупреждение не во всех случаях, когда слева и справа от оператора находятся одинаковые подвыражения.

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

    do {
    } while (*++scan == *++match && *++scan == *++match &&
             *++scan == *++match && *++scan == *++match &&
             *++scan == *++match && *++scan == *++match &&
             *++scan == *++match && *++scan == *++match &&
             scan < strend);

Данный код анализатор считает безопасным.

Второе исключение относится к сравнению двух одинаковых чисел. Этот прием часто используется программистами, чтобы выключить определенные ветки программы. Пример:

    #if defined(_OPENMP)
    #include <omp.h>
    #else
    #define omp_get_thread_num()   0
    ...
    #endif
    ...
    if (0 == omp_get_thread_num()) {

Последнее исключение относится к сравнению, где используются макросы:

    #define _WINVER_NT4_    0x0004
    #define _WINVER_95_     0x0004
    ...
    UINT    winver = g_App.m_pPrefs->GetWindowsVersion();
    if(winver == _WINVER_95_ || winver == _WINVER_NT4_)

Следует понимать, что в ряде случаев анализатор может выдать предупреждение на корректную конструкцию. Например, анализатор не учитывает побочные эффекты (side effects) при вызове функций:

    if (wr.takeChar() == '\0' && wr.takeChar() == '\0')

Другой пример ложного срабатывания анализатора был замечен на юнит-тестах одного проекта, в той его части, где проверялось корректность работы перегруженного оператора '==':

    CHECK(VDStringA() == VDStringA(), true);
    CHECK(VDStringA("abc") == VDStringA("abc"), true);

Диагностическое сообщение не выдается, если сравниваются два идентичных выражения типа float или double. Такое сравнение позволяет определить, является ли значение NaN. Пример кода, реализующего подобную проверку:

    bool isnan(double X) { return X != X; }

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

CWE-570 CWE-571

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