﻿# V102\. Usage of non memsize type for pointer arithmetic\.


> Это правило входит в группу "Диагностика 64\\\-битных ошибок"\\\. Разработка правил этой группы больше не ведётся, и в будущем они могут быть отключены\\\. Если вы используете эти правила, \[свяжитесь с нашей поддержкой\]\(https://pvs\-studio\.ru/ru/about\-feedback/\) — мы поможем найти замену или предложим альтернативное решение\\\.

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

Рассмотрим пример\.

```cpp
short a16, b16, c16;
char *pointer;
...
pointer += a16 * b16 * c16;
```

Данный пример корректно работает с указателями, если значение выражения "a16 \* b16 \* c16" не превышает 'INT\_MAX' \(2Гб\)\. Такой код мог всегда корректно работать на 32\-битной платформе, в силу того, что программа никогда не выделяла массивов больших размеров\. На 64\-битной архитектуре программиста, использующего старый код для работы с массивом большего размера, ждет разочарование\. Допустим, мы хотим сдвинуть значение указателя на 3000000000 байт, и по этому переменные 'a16', 'b16' и 'c16' имеют значения 3000, 1000 и 1000 соответственно\. При вычислении выражения "a16 \* b16 \* c16" все переменные, согласно правилам языка Си\+\+, будут приведены к типу int, а уже затем будет произведено их умножение\. В ходе выполнения умножения, произойдет переполнение, в результате которого будет получено число \-1294967296\. Некорректный результат выражения будет расширен до типа 'ptrdiff\_t' и произойдет вычисление указателя\. В результате нас будет ожидать аварийное завершение программы, при попытке использования некорректного указателя\.

Для предотвращения подобных ошибок следует использовать [memsize](https://pvs-studio.ru/ru/blog/terms/0030/) типы\. В нашем случае будет корректно заменить типы переменных 'a16', 'b16', 'c16' или использовать их [явное приведение](https://pvs-studio.ru/ru/blog/terms/0015/) к типу 'ptrdiff\_t', как показано ниже:

```cpp
short a16, b16, c16;
char *pointer;
...
pointer += static_cast<ptrdiff_t>(a16) *
      static_cast<ptrdiff_t>(b16) *
      static_cast<ptrdiff_t>(c16)
```

Хочется отметить, что не всегда использование в арифметике с указателями не [memsize](https://pvs-studio.ru/ru/blog/terms/0030/) типов является ошибочным\. Рассмотрим следующую ситуацию:

```cpp
char ch;
short a16;
int *pointer;
...
int *decodePtr = pointer + ch * a16;
```

Анализатор не выдает на нее сообщения, в силу ее корректности\. Здесь не происходит вычислений, которые могли бы привести к переполнению и результат этого выражения всегда будет корректен как на 32\-битной, так и на 64\-битной платформе\.

Дополнительные материалы по данной теме:

1. 64\-битные уроки\. Урок 13\. Паттерн 5\. [Адресная арифметика](https://pvs-studio.ru/ru/blog/lessons/0013/)\.