V510. The 'Foo' function receives class-type variable as 'N'th actual argument. This is unexpected behavior.
- Note about C++11
- Note one specific thing about using the CString class from the MFC library
- Related materials
Variadic function (a function whose last formal parameter is an ellipsis) takes an object of a class type as an actual argument that is part of an ellipsis, which may indicate a logical error. Only POD-types can serve as actual arguments for ellipsis.
POD is an abbreviation for "Plain Old Data", i.e. "Plain data in C style". The following types and structures refer to POD-types:
- Scalar types: possibly cv-qualified arithmetic (integral and floating-point), pointer, pointer to member, enumeration or 'std::nullptr_t';
- Class types ('class', 'struct', or 'union') that meet the following requirements:
- Every copy constructor (if any) is trivial (it is implicitly-defined or defaulted);
- Every move constructor (if any) is trivial;
- Every copy assignment operator (if any) is trivial;
- Every move assignment operator (if any) is trivial;
- Has a trivial non-deleted destructor;
- Has no virtual functions or virtual base classes;
- Has one or more default constructors, all of which are trivial;
- All non-static data members have the same access control;
- Has no virtual functions or virtual base classes;
- Has no non-static data members of reference type;
- All non-static data members and base classes are themselves standard layout types;
- Either has no base classes with non-static data members, or has no non-static data members in the most derived class and at most one base class with non-static data members;
- Has no base classes of the same type as the first non-static data member.
If a class object is passed to an ellipsis function, this almost always indicates an error in program. The V510 rule helps detect incorrect code of the following kind:
wchar_t buf[100];
std::wstring ws(L"12345");
swprintf(buf, L"%s", ws);
The object's contents are saved into the stack instead of the pointer to the string. This code will cause generating "abracadabra" in the buffer or a program crash.
The correct version of the code must look this way:
wchar_t buf[100];
std::wstring ws(L"12345");
swprintf(buf, L"%s", ws.c_str());
Since you might pass anything you like into functions with a variable number of arguments, almost all the books on C++ programming do not recommend using them. They suggest employing safe mechanisms instead, for instance, boost::format.
Note about C++11
In new standard, it is said that: 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.
Thus, it is possible to pass into function' ellipsis "more various kinds" of objects. However, we decided not to change anything in this rule. In 99% of cases transferring a complex class as an argument is a misprint or another kind of error. This code should be reviewed. In case of inconvenience caused by large amount of false alarms related to this warning, it is possible to mark these functions to suppress it massively. An example:
//-V:MySuperPrint:510
It is possible to read about multiple warning suppression in details in section "Suppression of false alarms".
Note one specific thing about using the CString class from the MFC library
We must see an error similar to the one mentioned above in the following code:
CString s;
CString arg(L"OK");
s.Format(L"Test CString: %s\n", arg);
The correct version of the code must look in the following way:
s.Format(L"Test CString: %s\n", arg.GetString());
Or, as MSDN suggests [1], you may use the explicit cast operator LPCTSTR implemented in the CString class to get a pointer to the string. Here is a sample of correct code from MSDN:
CString kindOfFruit = "bananas";
int howmany = 25;
printf("You have %d %s\n", howmany, (LPCTSTR)kindOfFruit);
However, the first version "s.Format(L"Test CString: %s\n", arg);" is actually correct as well like the others. This topic is discussed in detail in the article "Big Brother helps you" [2].
The MFC developers implemented the CString class in a special way so that you could pass it into functions of the printf and Format types. It is done rather intricately and if you want to make it out, study implementation of the CStringT class in the source codes.
So, the analyzer makes an exception for the CStringT type and considers the following code correct:
CString s;
CString arg(L"OK");
s.Format(L"Test CString: %s\n", arg);
Related materials
- MSDN. CString Operations Relating to C-Style Strings. https://www.microsoft.com/en-us/download/details.aspx?id=55979;
- Big Brother helps you. http://www.viva64.com/en/b/0073/
This diagnostic is classified as:
|
You can look at examples of errors detected by the V510 diagnostic. |