V501. There are identical sub-expressions to the left and to the right of the 'foo' operator

13.08.2013

The analyzer found a code fragment that most probably has a logic error. There is an operator (<, >, <=, >=, ==, !=, &&, ||, -, /) in the program text to the left and to the right of which there are identical subexpressions.

Consider an example:

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

In this case, the '&&' operator is surrounded by identical subexpressions "a.x != 0" and it allows us to detect an error made through inattention. The correct code that will not look suspicious to the analyzer looks in the following way:

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

Consider another example of an error detected by the analyzer in the code of a real application:

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

In this case, the code is senseless though it is compiled successfully and without any warnings. Correct code must look as follows:

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

The analyzer does not generate the warning in all the cases when there are identical subexpressions to the left and to the right of the operator.

The first exception refers to those constructs where the increment operator ++, the decrement operator - or += and -= operator are used. Here is an example taken from a real application:

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

The analyzer considers this code safe.

The second exception refers to comparison of two equal numbers. Programmers often employ this method to disable some program branches. Here is an example:

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

The last exception refers to comparison that uses macros:

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

You should keep in mind that the analyzer might generate a warning on a correct construct in some cases. For instance, the analyzer does not consider side effects when calling functions:

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

Another example of a false alarm was noticed during unit-tests of some project - in the part of it where the correctness of the overloaded operator '==' was checked:

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

The diagnostic message isn't generated if two identical expressions of 'float' or 'double' types are being compared. Such a comparison allows to identify the value as NaN. The example of code implementing the verification of this kind:

bool isnan(double X) { return X != X; }
You can look at examples of errors from real projects which were detected by this diagnostic message.