Many
See 'Dataflow Analysis Issues' for a summary of the various dataflow analysis 'issues'.
Strictly speaking, a constant message is not a dataflow analysis message at all. It identifies an issue which can be deduced without analysis of control flow or the status of variables. For example:
extern void foo(void)
{
int buf[25] = {0};
...
buf[100] = 0; /* Message 2840 */
...
An array bounds violation in this code is identified because the array subscript value is a constant expression and it can be deduced that the assignment operation addresses an array element outside the declared bounds of the array. The problem would be identified as follows:
2840: Constant: Dereference of an invalid pointer value.
A definite message identifies an issue which will definitely occur. For example:
extern void f1(unsigned int n)
{
int buf[10] = {0};
if (n > 10)
{
buf[n] = 100; /* Message 2841 */
}
...
Perhaps the programmer used a '>' operator by mistake instead of a '<' in the 'if' statement. The result of this mistake is, of course, an array bounds violation; the value 100 will be assigned to an element which is outside the bounds of the array. This problem would be identified as follows:
2841: Definite: Dereference of an invalid pointer value.
Another example ...
extern void f2(void)
{
int buf[10];
int *p;
p = buf;
...
p[100] = 0; /* Message 2841 */
}
In this code, the array bounds violation occurs indirectly through a pointer. Dataflow analysis of the code determines that the size of the object addressed by the pointer 'p' and deduces that the array subscript operation will result in the dereferencing of an invalid pointer value.
Notice that a definite message does not imply that the issue will occur every time the statement is executed (e.g. on every iteration of a loop), but it will definitely occur if the statement is ever reachable. For example, a definite array bounds violation message may be generated in the context of a loop even though the violation may not occur on every iteration of the loop. For example:
extern void f3(void)
{
int buf[10];
int i;
for (i = 0; i <= 10; ++i)
{
buf[i] = i; /* Message 2841 */
}
}
An apparent message identifies an issue that will occur unless a specific path elsewhere in the code, associated with an if or switch statement of a conditional operation (? :) is always redundant. In other words, if the apparent condition is not to occur, it implies that there must be a redundant path elsewhere.
Consider the following example. The code exhibits an anomaly: the code controlled by the if statement is only reachable if the value of 'n' exceeds 10, and if this happens, an array bounds violation will occur when referencing 'buf[n]'.
extern void f1(unsigned int n)
{
int buf[10];
if (n > 10) /* Redundant path ? - No message */
{
...
}
...
buf[n] = 100; /* Array bounds violation ? - Message 2842 */
}
There is therefore an array bounds problem UNLESS the 'if' statement gives rise to a redundant path. The following message will be generated:
2842: Apparent: Dereference of an invalid pointer value.
The same message will be generated if the relational operator as changed as shown below, because a different redundant path now exists.
extern void f2(unsigned int n)
{
int buf[10];
if (n < 10) /* Redundant path ? - No message */
{
...
}
...
buf[n] = 100; /* Array bounds violation ? - Message 2842 */
}
In each of the above examples, the code can be considered to reflect 2 contradictory assumptions:
Both examples illustrate instances of what may be described as regular apparent conditions. There are other similar situation which exhibit the same anomaly but where the array reference precedes the redundant path condition. These are described as reverse apparent conditions. See the following example:
extern void f3(unsigned int n)
{
int buf[10];
buf[n] = 100; /* Array bounds violation ? - Message 2842 */
...
if (n > 10) /* Redundant path ? - No message */
{
...
}
}
A suspicious message identifies an issue that will occur unless certain conditions are fulfilled in the execution of a loop construct.
Notice that apparent and suspicious messages both identify issues associated with the use of paths. However ...
Suspicious messages are therefore informational in nature and are less specific than apparent messages. They do not necessarily identify that a real problem exists but merely attempt to expose assumptions that may have been made unwittingly.
Consider two examples which both generate message 2843:
2843: Suspicious: Dereference of an invalid pointer value.
Example 1: An array bounds violation will occur unless:
void path_never_executed (int i)
{
int array[5];
int j = 10;
int k;
for (k = 0; k < 10; ++k) {
if (i > k)
j = 0; /* AAA */
}
array[j] = 0; /* Message 2843 */
}
Example 2: An array bounds violation will occur unless:
void path_executed_on_last_iter (int i)
{
int array[5];
int j = 0;
int k;
for (k = 0; k < 10; ++k) {
if (i > k)
j = 10;
else
j = 0; /* AAA */
}
array[j] = 0; /* Message 2843 */
}
A possible message identifies situations about which there is uncertainty, either because of the limitations of the dataflow analysis engine or because the code is not written in a way which allows a more definitive conclusion to be drawn. In practice, unless code is developed defensively with a high degree of discipline, possible messages will be encountered frequently.
Possible messages are not implemented for all dataflow conditions because their usefulness would be very limited. Consider the following:
extern void foo(unsigned int n)
{
unsigned int m;
m = 1000 / n; /* Message 2834 */
}
Because the value of the function parameter 'n' on entry is considered to be unknown, QAC will generate message 2834 to indicate that the divisor could be zero.
2834: Possible: Division by zero.