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


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

Calls of some functions are senseless if their results are not used.

Let's study the first sample:

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

This value emptying code is taken from a real application. The error here is the following: by accident, the 'empty' function is called instead of the 'clear' function of the 'std::string' object, and the line's content remains unchanged. The analyzer detects this error relying on knowledge that the result of the 'empty' function must be used. For instance, it must be compared to something or written into a variable.

This is the correct code:

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

The second sample:

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

The 'std::remove' function does not remove elements from the container. It only shifts the elements and brings the iterator back to the beginning of the trash. Suppose we have the vector<int> container that contains elements 1,2,3,1,2,3,1,2,3. If we execute the code "remove( v.begin(), v.end(), 2 )", the container will contain elements 1,3,1,3,?,?,?, where ? is some trash. The function will bring the iterator back to the first senseless element, so if we want to remove these trash elements, we must write the code this way: "v.erase(remove(v.begin(), v.end(), 2), v.end())".

As you may see from this explanation, the result of 'std::remove' must be used. This is the correct code:

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

There are very many functions whose results must be used. Among them are the following: 'malloc', 'realloc', 'fopen', 'isalpha', 'atof', 'strcmp' and many, many others. An unused result signals an error which is usually caused by a misprint. However, the analyzer warns only about errors related to using the standard library. There are two reasons for that:

1) It is much more difficult to make a mistake by not using the result of the 'fopen' function than confuse 'std::clear' and 'std::empty' .

2) This functionality duplicates the capabilities of Code Analysis for C/C++ included into some Visual Studio editions (see warning C6031). But these warnings are not implemented in Visual Studio for standard library functions.

If you want to propose extending the list of functions supported by analyzer, contact our support service. We will appreciate if you give interesting samples and advice.

Security

In addition to straightforward bugs and typos, security is another area to be taken into account. There are functions that deal with access control, such as LogonUser and SetThreadToken, but there are many more. One must always check on the statuses returned by these functions. Not using these return values is a grave mistake and potential vulnerability - this is why the analyzer issues warning V530 for such functions as well.

Additional features

You can specify the names of user functions for which it should be checked if their return values are used.

To enable this option, you need to use custom annotations. Insert a special comment near the function prototype (or in the common header file), for example:

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

Format:

  • The 'function' key specifies the full name of the function, which consists of the namespace name, the class name, and the function name. Nested namespaces and nested classes are supported.

In projects with special quality requirements, you might need to find all functions, the return value of which is not used. To do this, you can use the 'RET_USE_ALL' custom annotation. If you want to know more, read the documentation for custom annotations.

Note. Custom annotations are not applied to virtual functions by default. You can read about how to enable this feature here.

This diagnostic is classified as:

You can look at examples of errors detected by the V530 diagnostic.