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

Вебинар: C++ и неопределённое поведение - 27.02

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

V1112. Comparing expressions with different signedness can lead to unexpected results.

02 Авг 2024

Анализатор обнаружил подозрительное сравнение, в котором типы выражений имеют одинаковый ранг, но разные знаки. При этом ранги типов меньше, чем у 'int'. Из-за неявного преобразования таких выражений к типу 'int' или 'unsigned int' сравнение может приводить к неожиданным результатам.

Рассмотрим синтетический пример:

bool foo(char lhs, unsigned char rhs)
{
  return lhs == rhs; // <=
}

В примере присутствует сравнение переменных с типами разной знаковости: 'lhs' типа 'char' и 'rhs' типа 'unsigned char'. Будем считать, что нижележащий тип 'char' — это 'signed char' (например, на архитектуре x86_64). Тип 'unsigned char' может отразить диапазон значений от [0 .. 255], при этом тип 'char' – [-128 .. 127]. Согласно стандартам C и C++, перед сравнением значений переменных должно произойти неявное преобразование типов (integral promotion), в результате которого и может возникнуть проблема.

Компилятор превращает код со сравнением в следующий:

return (int) lhs == (int) rhs;

Такое преобразование он делает, если тип 'int' может отобразить диапазон значений 'char' и 'unsigned char', иначе вместо 'int' выберется 'unsigned int'. На большинстве современных платформ тип 'int' занимает 4 байта и с лёгкостью может отобразить эти диапазоны.

В случае, если 'lhs' имел отрицательное значение, то оно же и сохранится в результате преобразования в левом операнде. При этом значение правого операнда после преобразования 'rhs' всегда будет неотрицательным, т.к. исходный тип был беззнаковым. В итоге результат сравнения будет вычисляться как 'false'. Возможна и обратная ситуация. Если в переменной 'rhs' находится значение в диапазоне [128 .. 255], то в этой ситуации результат сравнения будет также 'false'.

Такая ошибка может неожиданно проявить себя при смене компилятора или настроек, когда ранее тип 'char' был беззнаковым, а стал знаковым, и наоборот. Например, в таком случае при вызове функции 'foo' с аргументами '\xEE' и '\xEE' будет считаться, что переданы неравные значения. Хотя такое поведение логично с точки зрения стандарта, оно может быть неожиданным для разработчика.

Ошибки можно избежать двумя способами.

Способ N1. Преобразовать выражения к общему типу по знаку:

if ((unsigned char) lhs == rhs)

Способ N2. Воспользоваться семейством функций 'std::cmp_*' (С++20) или их аналогами для сравнения выражений, типы которых имеют различную знаковость:

if (std::cmp_equal(lhs, rhs))

Примечание. В диагностическом правиле реализованы несколько исключений, которые добавлены для уменьшения количества ложных срабатываний. Анализатор выдаёт срабатывание лишь в том случае, если он смог доказать, что диапазон значений одного из операндов не может быть отображён типом другого операнда. Если же требуется выявить все места в коде, где происходит такое сравнение операндов, разных по знаковости, можно воспользоваться следующим комментарием:

//+V1112, ENABLE_ON_UNKNOWN_VALUES

По этой причине анализатор не выдаёт срабатывание на приведённом ранее синтетическом примере без этой настройки.

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки целочисленного переполнения и некорректного совместного использования знаковых и беззнаковых чисел.

Данная диагностика классифицируется как:

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
Ваше сообщение отправлено.

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


Если вы так и не получили ответ, пожалуйста, проверьте, отфильтровано ли письмо в одну из следующих стандартных папок:

  • Промоакции
  • Оповещения
  • Спам