metrica
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо
to the top
close form

Заполните форму в два простых шага ниже:

Ваши контактные данные:

Шаг 1
Поздравляем! У вас есть промокод!

Тип желаемой лицензии:

Шаг 2
Team license
Enterprise license
** Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности
close form
Запросите информацию о ценах
Новая лицензия
Продление лицензии
--Выберите валюту--
USD
EUR
RUB
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Бесплатная лицензия PVS‑Studio для специалистов Microsoft MVP
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Для получения лицензии для вашего открытого
проекта заполните, пожалуйста, эту форму
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
Мне интересно попробовать плагин на:
* Нажимая на кнопку, вы даете согласие на обработку
своих персональных данных. См. Политику конфиденциальности

close form
check circle
Ваше сообщение отправлено.

Мы ответим вам на


Если вы так и не получили ответ, пожалуйста, проверьте папку
Spam/Junk и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

Вебинар: Трудности при интеграции SAST, как с ними справляться - 04.04

>
>
>
V221. Suspicious sequence of types cast…
menu mobile close menu
Проверка проектов
Сообщения PVS-Studio
Диагностики общего назначения (General Analysis, C++)
Диагностики общего назначения (General Analysis, C#)
Диагностики общего назначения (General Analysis, Java)
Микрооптимизации (C++)
Диагностика 64-битных ошибок (Viva64, C++)
Реализовано по запросам пользователей (C++)
Cтандарт MISRA
Стандарт AUTOSAR
Стандарт OWASP (C#)
Проблемы при работе анализатора кода
Дополнительная информация
toggle menu Оглавление

V221. Suspicious sequence of types castings: pointer -> memsize -> 32-bit integer.

05 Мар 2015

Предупреждение информирует о наличии странной последовательности приведений типа. Указатель явно приводится к memsize-типу. А затем вновь явно или неявно приводится к 32-битному целочисленному типу. Такая последовательность приведений приводит к потере значений старших бит. Как правило, это свидетельствует о наличии серьезной ошибки.

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

int *p = Foo();
unsigned a, b;
a = size_t(p);
b = unsigned(size_t(p));

В обоих случаях указатель преобразовывается в тип 'unsigned'. При этом старшая часть указателя будет потеряна. Если затем переменные 'a' или 'b' вновь превратить в указатель, эти указатели могут оказаться некорректными.

Различие между переменными 'a' и 'b' только в том, что второй случай тяжелей обнаружить. В первом случае, компилятор предупредит о потери значащих бит. Во втором случае он будет молчать, так как используется явное приведение типа.

Исправление ошибки заключается в том, чтобы хранить указатели только memsize-типах, например, в переменных типа size_t:

int *p = Foo();
size_t a, b;
a = size_t(p);
b = size_t(p);

Иногда некоторое недопонимание вызывает предупреждение анализатора на код следующего вида:

BOOL Foo(void *ptr)
{
  return (INT_PTR)ptr;
}

Тип BOOL это не что иное как 32-битный тип 'int'. Поэтому возникает цепочка преобразований вида:

pointer -> INT_PTR -> int.

Может показаться, что здесь ошибки нет. Ведь нам только важно, что указатель равен или не раен нулю. Но на самом деле ошибка есть. Не следует путать как ведёт себя тип BOOL и bool.

Пусть у нас есть 64-битная переменная, значение которой равно 0x000012300000000. Тогда при приведении к bool и BOOL мы получим разные результаты:

int64_t v = 0x000012300000000ll;

bool b = (bool)(v); // true

BOOL B = (BOOL)(v); // FALSE

В случае 'BOOL' просто будут отброшены старшие биты. И ненулевое значение превратится в 0 (FALSE).

Аналогичная ситуация с указателем. При явном приведении указателя к BOOL отпросятся старшие биты и ненулевой указатель превратится в целочисленный 0 (FALSE). Вероятность такого события мала, но есть. Поэтому такой код неверен.

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

bool Foo(void *ptr)
{
  return (INT_PTR)ptr;
}

Хотя конечно лучше и проще написать так:

bool Foo(void *ptr)
{
  return ptr != nullptr;
}

Показанный выше вариант не всегда возможен. Например, в языке Си нет типа 'bool'. Второй вариант исправления ошибки:

BOOL Foo(void *ptr)
{
  return ptr != NULL;
}

Следует учитывать, что анализатор не выдаёт предупреждение, если конвертации подвергается такие типы данных, как HANDLE, HWND, HCURSOR и так далее. Хотя по сути это указатели (void *), их значения всегда вмещаются в младшие 32-бита. Это сделано специально, чтобы эти дескрипторы (handles) можно было передавать между 32-битными и 64-битными процессами. Подробнее: Как корректно привести указатель к int в 64-битной программе?