﻿# 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\.

Анализатор обнаружил потенциальную ошибку в выражении, где используются операции сдвига \(shift operations\)\. В процессе сдвига возникает переполнение, и значения старших бит будут потеряны\.

Для начала рассмотрим эту ситуацию на простом примере:

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

Значение выражения `77u << 26` равно 5167382528 \(0x134000000\)\. При этом выражение `77u << 26` имеет тип `unsigned int`\. Это значит, что старшие биты будут отброшены, и будет напечатано значение `872415232 (0x34000000)`\.

Переполнения, возникающие при сдвигах, часто указывают на наличие логической ошибки или просто опечатки\. Например, может быть, что число `77u` хотели задать в восьмеричной системе счисления\. Тогда корректный код должен выглядеть так:

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

Здесь переполнения уже не возникает\. Значение выражения `077u << 26` равно `4227858432 (0xFC000000)`\.

Если хочется распечатать значение `5167382528`, то число 77 должно быть задано с помощью 64\-битного типа\. Например, так:

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

Перейдём к случаям, с которыми можно встретиться на практике\. Для этого рассмотрим две ошибки, обнаруженные в реальных приложениях\.

Первый пример\.

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

Программист хотел записать в 64\-битную переменную `uSmallestSAD` значение `0x7FFFFFF00`\. Но на самом деле переменная будет иметь значение 0xFFFFFF00\. Старшие биты будут отброшены, так как выражение `MAX_SAD<<8` имеет тип `int`\. Программист знал про это, поэтому решил использовать явное приведение типа, но ошибся, расставляя скобки\. Этот пример хорошо демонстрирует, что подобные ошибки могут возникать из\-за простой опечатки\. Корректный код:

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

Второй пример\.

```cpp
#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);
```

Функция должна сформировать информацию об ошибке в переменной типа `HRESULT`\. Для этого программист использовал макрос `MAKE_HRESULT`, но сделал это неправильно, посчитав, что первый параметр `severity` может лежать в приделах от 0 до 3\. Вероятно, он перепутал это со способом формирования кодов ошибки, используемом при работе с функциями `GetLastError()` / `SetLastError()`\.

Макрос `MAKE_HRESULT` в качестве первого аргумента может принимать только 0 \(success\) или 1 \(failure\)\. Подробнее этот вопрос рассматривался на форуме сайта CodeGuru: [Warning\! MAKE\_HRESULT macro doesn't work](https://forums.codeguru.com/showthread.php?145615-warning!-make_hresult-macro-doesn-t-work!)\.

Так как в качестве первого фактического аргумента используется число 3, то возникает переполнение\. Число 3 "превратится" в 1\. Из\-за этой случайности ошибка не повлияет на работу программы\. Однако приведённый пример показывает, что нередко код работает исключительно благодаря везению, а не потому, что написан правильно\.

Правильный код:

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