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 и нажмите на письме кнопку "Не спам".
Так Вы не пропустите ответы от нашей команды.

>
>
>
V510. The 'Foo' function receives class…
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 Оглавление

V510. The 'Foo' function receives class-type variable as 'N'th actual argument. This is unexpected behavior.

15 Дек 2011

Вариативная функция (функция, последним формальным параметром которой является эллипсис) принимает в качестве фактического аргумента, являющегося частью эллипсиса, объект классового типа, что может свидетельствовать о логической ошибке. В качестве фактического параметра для эллипсиса могут выступать только POD типы.

POD – это аббревиатура от "Plain Old Data", что можно перевести как "Простые данные в стиле Си". Начиная с C++11, к POD-типам относятся:

  • Скалярные типы: арифметические типы (целые и вещественные), указатели, указатели на нестатические поля или функции класса, перечисления ('enum') или 'std::nullptr_t' (могут быть 'const' / 'volatile' квалифицированными);
  • Классовый тип ('class', 'struct' или 'union'), который удовлетворяет нижеприведенным требованиям:
    • Конструкторы копирования/перемещения тривиальны (сгенерированы компилятором или помечены как '= default');
    • Операторы копирования/перемещения тривиальны (сгенерированы компилятором или помечены как '= default');
    • Имеет неудаленный тривиальный деструктор;
    • Не имеет виртуальных функций или виртуальных базовых классов;
    • Конструктор по умолчанию тривиален (сгенерирован компилятором или помечен как '= default');
    • Все нестатические поля имеют одинаковый доступ ('private', 'protected' или 'public');
    • Не имеет виртуальных функций или виртуальных базовых классов;
    • Не имеет нестатических полей ссылочного типа;
    • Все нестатические поля и базовые классы имеют тип со стандартным размещением в памяти;
    • Не имеют базовых классов с нестатическими полями, или не имеют полей в самом производном классе и не более одного базового класса с нестатическими полями;
    • Не имеют базовых классов того же типа, что имеет первое нестатическое поле;

Если эллипсис функции в качестве параметра передается объект класса, то практически всегда свидетельствует о наличии ошибки в программе. На практике правило V510 помогает выявить ошибочный код следующего вида:

wchar_t buf[100];
std::wstring ws(L"12345");
swprintf(buf, L"%s", ws);

Вместо указателя на строку в стек попадает содержимое объекта. Такой код приведет к формированию в буфере "абракадабры" или к аварийному завершению программы.

Корректный вариант кода должен выглядеть так:

wchar_t buf[100];
std::wstring ws(L"12345");
swprintf(buf, L"%s", ws.c_str());

Из-за того, что в функции с переменным количеством аргументов можно передать все что угодно, их и не рекомендуют использовать практически во всех книгах по программированию на языке Си++. Вместо этого предлагается использовать безопасные механизмы, например, boost::format.

Примечание касательно C++11

Новый стандарт говорит: C++11 5.2.2/7: Passing a potentially-evaluated argument of class type having a non-trivial copy constructor, a non-trivial move constructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics.

Таким образом, можно передавать в эллипсис функции "более разнообразные" объекты. Однако мы не стали ничего менять в диагностическом правиле. В 99% передача сложного класса в качестве аргумента является опечаткой или иной ошибкой. Такой код стоит проверить. Если ложные срабатывания доставляют неудобства, можно разметить функции специальным образом. Пример:

//-V:MySuperPrint:510

Подробнее о массовом подавлении предупреждений можно прочитать в разделе "Подавление ложных предупреждений".

Отметим особенность, связанную с использованием класса CString из библиотеки MFC

Ошибку аналогичную приведенной выше, мы должны наблюдать и в следующем коде:

CString s;
CString arg(L"OK");
s.Format(L"Test CString: %s\n", arg);

Корректный вариант кода должен выглядеть так:

s.Format(L"Test CString: %s\n", arg.GetString());

Или как предлагается в MSDN [1] для получения указателя на строку можно использовать явный оператор приведения LPCTSTR, реализованный в классе CString. Пример корректного кода из MSDN:

CString kindOfFruit = "bananas";
int howmany = 25;
printf("You have %d %s\n", howmany, (LPCTSTR)kindOfFruit);

Однако, на самом деле первый вариант "s.Format(L"Test CString: %s\n", arg);" также является корректным, как и остальные. Подробнее эта тема обсуждается в статье "Большой брат помогает тебе" [2].

Разработчики MFC реализовали класс CString специальным образом, так, чтобы его можно было передавать в функции вида printf и Format. Сделано это достаточно хитро и кто интересуется, тот может ознакомиться с реализацией в исходных кода класса CStringT.

Таким образом, анализатор делает исключение для типа CStringT и считает следующий код корректным:

CString s;
CString arg(L"OK");
s.Format(L"Test CString: %s\n", arg);

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

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

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V510.

Unicorn with delicious cookie
Мы используем куки, чтобы пользоваться сайтом было удобно.
Хорошо