>
>
>
V5006. OWASP. More than N bits are requ…


V5006. OWASP. More than N bits are required to store the value, but the expression evaluates to the T type which can only hold K bits.

The analyzer has detected a potential error in an expression using shift operations. Shift operations cause an overflow and loss of the high-order bits' values.

Let's start with a simple example:

std::cout << (77u << 26);

The value of the "77u << 26" expression equals 5167382528 (0x134000000) and is of the 'unsigned int' type at the same time. It means that the high-order bits will be truncated and you'll get the value 872415232 (0x34000000) printed on the screen.

Overflows caused by shift operations usually indicate a logic error or misprint in the code. It may be, for example, that the programmer intended to define the number '77u' as an octal number. If this is the case, the correct code should look like this:

std::cout << (077u << 26);

No overflow occurs now; the value of the "077u << 26" expression is 4227858432 (0xFC000000).

If you need to have the number 5167382528 printed, the number 77 must be defined as a 64-bit type. For example:

std::cout << (77ui64 << 26);

Now let's see what errors we may come across in real life. The two samples shown below are taken from real applications.

Example 1.

typedef __UINT64 Ipp64u;
#define MAX_SAD 0x07FFFFFF
....
Ipp64u uSmallestSAD;
uSmallestSAD = ((Ipp64u)(MAX_SAD<<8));

The programmer wants the value 0x7FFFFFF00 to be written into the 64-bit variable uSmallestSAD. But the variable will store the value 0xFFFFFF00 instead, as the high-order bits will be truncated because of the MAX_SAD<<8 expression being of the 'int' type. The programmer knew that and decided to use an explicit type conversion. Unfortunately, he made a mistake when arranging parentheses. This is a good example to demonstrate that such bugs can easily be caused by ordinary mistakes. This is the fixed code:

uSmallestSAD = ((Ipp64u)(MAX_SAD))<<8;

Example 2.

#define MAKE_HRESULT(sev,fac,code) \
  ((HRESULT) \
   (((unsigned long)(sev)<<31) | \
    ((unsigned long)(fac)<<16) | \
    ((unsigned long)(code))) )

*hrCode = MAKE_HRESULT(3, FACILITY_ITF, messageID);

The function must generate an error message in a HRESULT-variable. The programmer uses the macro MAKE_HRESULT for this purpose, but in a wrong way. He suggested that the range for the first argument 'severity' was to be from 0 to 3 and must have mixed these figures up with the values needed for the mechanism of error code generation used by the functions GetLastError()/SetLastError().

The macro MAKE_HRESULT can only take either 0 (success) or 1 (failure) as the first argument. For details on this issue see the topic on the CodeGuru website's forum: Warning! MAKE_HRESULT macro doesn't work.

Since the number 3 is passed as the first actual argument, an overflow occurs. The number 3 "turns into" 1, and it's only thanks to this that the error doesn't affect program execution. I've given you this example deliberately just to show that it's a frequent thing when your code works because of mere luck, not because it is correct.

The fixed code:

*hrCode = MAKE_HRESULT(SEVERITY_ERROR, FACILITY_ITF, messageID);

This diagnostic is classified as: