>
>
>
V530. Return value of 'Foo' function is…


V530. Return value of 'Foo' function is required to be used.

Вызов некоторых функций не имеет смысла, если результат их работы не используется.

Рассмотрим первый пример:

void VariantValue::Clear()
{
  m_vtype = VT_NULL;
  m_bvalue = false;
  m_ivalue = 0;
  m_fvalue = 0;
  m_svalue.empty();
  m_tvalue = 0;
}

Этот код очистки значений взят из реального приложения. Ошибка заключается в том, что вместо функции 'clear' объекта 'std::string' случайно вызывается функция 'empty', и содержимое строки остается неизменным. Ошибка диагностируется на основании того, что результат работы функции 'empty' обязательно должен быть использован. Например, результат должен быть с чем-то сравнен или записан в переменную.

Исправленный вариант кода:

void VariantValue::Clear()
{
  m_vtype = VT_NULL;
  m_bvalue = false;
  m_ivalue = 0;
  m_fvalue = 0;
  m_svalue.clear();
  m_tvalue = 0;
}

Второй пример:

void unregisterThread() {
  Guard<TaskQueue> g(_taskQueue);
  std::remove(_threads.begin(), _threads.end(),
              ThreadImpl::current());
}

Функция 'std::remove' не удаляет элементы из контейнера. Она только сдвигает элементы и возвращает итератор на начало мусора. Пусть мы имеем контейнер 'vector<int>', содержащий элементы 1,2,3,1,2,3,1,2,3. Если выполнить код "remove( v.begin(), v.end(), 2 )", то контейнер будет содержать элементы 1,3,1,3,?,?,?, где ? - некий мусор. При этом функция вернет итератор на первый мусорный элемент, и если мы хотим удалить эти мусорные элементы, то должны написать код: "v.erase(remove(v.begin(), v.end(), 2), v.end())".

Как видно из объяснения, результат 'std::remove' должен быть обязательно использован. Корректный код:

void unregisterThread() {
  Guard<TaskQueue> g(_taskQueue);
  auto trash = std::remove(_threads.begin(), _threads.end(),
                           ThreadImpl::current());
  _threads.erase(trash, _threads.end());
}

Функций, результат которых должен быть обязательно использован, огромное количество. К ним можно отнести: 'malloc', 'realloc', 'fopen', 'isalpha', 'atof', 'strcmp' и многие, многие другие функции. Неиспользуемый результат свидетельствует об ошибке, чаще всего связанной с допущенной опечаткой. Однако анализатор предупреждает только об ошибках, связанных с использованием стандартной библиотеки. На это имеется две причины:

1) Допустить ошибку, не используя результат такой функции, как 'fopen' намного сложней, чем спутать 'std::clear' и 'std::empty'.

2) Данная функциональность будет дублировать возможности Code Analysis for C/C++, входящий в состав некоторых редакций Visual Studio (смотри предупреждение C6031). Однако в Visual Studio эти предупреждения не реализованы для функций стандартной библиотеки.

Если вы хотите предложить расширить список функций, поддерживаемых анализатором, то обратитесь в поддержку. Мы будем благодарны за интересные примеры и советы.

Безопасность

Помимо явных ошибок и опечаток, следует рассмотреть тему безопасности. Существуют функции, связанные с разграничением доступа. В качества примера назовём только функции LogonUser и SetThreadToken, но на самом деле их много. Нужно обязательно проверять статусы, которые возвращают эти функции. Неиспользование значений, которые вернули эти функции, является грубой ошибкой и потенциальной уязвимостью. Именно поэтому для таких функций анализатор также выдает предупреждение V530.

Дополнительные возможности

Можно указать имена пользовательских функций, для которых следует выполнять проверку, используется ли возвращаемое функцией значение.

Для этого используется специальная пользовательская аннотация. Пример использования:

//+V530, function: MyNamespace::MyClass::MyFunc
namespace MyNamespace {
  class MyClass {
    int MyFunc();
  }
  ....
  obj.MyFunc(); // warning V530
}

Формат:

  • Ключ 'function' задаёт полное имя функции, состоящее из названия пространства имён, имени класса и имени функции. Поддерживаются вложенные пространства имён и вложенные классы.

В проектах с особыми требованиями качества может понадобиться найти все функции, возвращаемое значение которых не используется. Для этого можно воспользоваться пользовательской аннотацией 'RET_USE_ALL'. Подробнее об этом можно прочитать в документации по пользовательским аннотациям.

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

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

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