The analyzer has detected a potential error: the function receives a suspicious value as an actual argument.
The example:
bool Matrix4::operator==(const Matrix4 &other) const
{
if (memcmp(this, &other, sizeof(Matrix4) == 0))
return true;
....
}
Here is a typo: a parenthesis is misplaced. Unfortunately, this error may go unnoticed and exist in the code for a long time. Due to this typo, the size of compared memory is evaluated with the sizeof(Matrix4) == 0
expression. Since the expression result is false
, 0 memory bytes are compared. The fixed code:
bool Matrix4::operator==(const Matrix4 &other) const
{
if (memcmp(this, &other, sizeof(Matrix4)) == 0)
return true;
....
}
Here is another example. The diagnostic rule detects cases where an array consisting of enum
elements is filled using the memset
function and one element size is unequal to one byte. The filling will not operate correctly because it is not each element but rather each byte that will get filled with a value.
The example of incorrect code:
enum E { V0, V1, V2, V3, V4 };
E array[123];
memset(array, V1, sizeof(array));
If the compiler allocates 4 bytes for each element, then each element will have the 0x01010101
value instead of the expected 0x00000001 (V1)
.
To fill the array correctly, the code should be modified as follows:
for (size_t i = 0; i < sizeof(array) / sizeof(array[0]); ++i)
{
array[i] = V1;
}
Another way to fix:
std::fill(begin(array), end(array), V1);
Note. NULL is a suspicious argument.
Sometimes developers use constructs like the one below to evaluate the amount of memory required for a buffer:
const char* format = getLocalizedString(id, resource);
int len = ::vsprintf(NULL, format, args);
char* buf = (char*) alloca(len);
::vsprintf(buf, format, args);
However, it is important to remember that calling ::vsprintf(NULL, format, args)
is incorrect. Here is what MSDN has to say about it:
int vsprintf(*buffer, char *format, va_list argptr);
....
vsprintf and vswprintf return the number of characters written, not including the terminating null character, or a negative value if an output error occurs. If buffer or format is a null pointer, these functions invoke the invalid parameter handler, as described in Parameter Validation. If execution is allowed to continue, these functions return -1 and set errno to EINVAL.
There are several options for additional configuration of this diagnostic rule.
The diagnostic rule relies on information about whether a particular pointer could be null. In some cases, this information is retrieved from the table of annotated functions, which is stored within the analyzer.
One of such functions is malloc
, which can return NULL
. Using the pointer returned by malloc
without a prior check may result in null dereference.
Sometimes users would like to change the analyzer behavior to assume that malloc
cannot return NULL
. For example, they can use the system libraries that handle out-of-memory errors in a specific way.
To indicate to the analyzer the function that can return a null pointer, use the additional settings, described in the section "How to tell the analyzer that a function can or cannot return nullptr".
If a function accepts the boundaries of a range as parameters, the corresponding parameters can be marked as the lower and upper bounds. This provides the analyzer with additional information that helps identify precondition violations (e.g., the lower bound value being greater than the upper bound).
To mark parameters as the lower and upper bounds, use the user annotation mechanism in JSON and the lower_bound
and upper_bound
attributes, respectively. Additionally, if there is a parameter which value is checked to be within the range, it should be marked as in_range_value
. If there is no such parameter, marking only the lower and upper bounds is enough.
The example. There is a function semantically similar to std::clamp
with the following signature:
bool foo(int v, int lo, int hi);
The function checks that the value of the first parameter lies within the range provided by the second (lower bound) and third (upper bound) parameters.
Let's say there is the following function call:
if (foo(x, 100, 0))
{
....
}
The arguments for the lower and upper bounds are swapped. To get the warning on the function call, mark the first parameter of the foo
function as in_range_value
, the second as lower_bound
, and the third as upper_bound
.
The fixed code:
if (foo(x, 0, 100))
{
....
}
See the examples of function parameter annotations here.
Note. This annotation is required only for user-defined functions.
This diagnostic is classified as:
|
You can look at examples of errors detected by the V575 diagnostic. |