Definitions and Uses
10.3.1 Definitions and Uses
The life of a program variable during the execution of a program lasts from the time the variable becomes known as part of the program state to the time it is no longer accessible to the program as part of the state. Under static block-structured dynamic
10.3 DATA FLOW COVERAGE 215
allocation, the name of a variable is known from the time of its declaration to the time when execution of the program exists the block where it is declared; under dynamic memory allocation, the name of a variable is known between the time the program creates the variable through an instantiation (by means of a new statement), and the time when the program explicitly returns the name (implicitly relinquishing the memory space to which it refers) or terminates its execution. Several relevant events arise during the lifecycle of a variable, including:
• Assignment of a value to the variable, through an assignment statement, or through a read statement, or at instantiation time through invocation of the con- structor method of a class, or at declaration time through compiler-generated initializations, or through parameter passing of the variable as a reference parameter to a routine. We refer to these events as definitions of the variable.
• Use of the value of the variable, to compute an expression, or through a write statement, or in a branch condition, or as an index to an array, or through param- eter passing of the variable as a value parameter to a routine. We refer to these events as uses of the variable, and we distinguish between ○ c-uses, when the variable is used to compute an expression and ○ p-uses, when the variable is used to compute a Boolean condition that affects
the program control. Notice that the same variable may be considered c-used and p-used if it inter- venes in an expression to compute a Boolean condition; such is the case, for example, for variable x in the following Boolean condition:
if ((x+2)>0) {…;}
Notice also that in a statement such as
a[i]=x+3;
for example, we consider that a is defined, i is c-used (even though it is used to compute an address/a location rather than a value), and x is c-used; strictly speak- ing, this statement only defines the ith cell of array a, but since we cannot identify the exact cell that has been modified, we assume that all of a has been (re-) defined.
• Termination of the lifecycle of the variable, when the variable is no longer part of the state of the program, either because control has exited the block where it was declared (in block structured programs) or because it has been explicitly relinquished (as is the case with some dynamic allocation schemes) or the program terminates its execution.
As an illustration of definitions and uses, we consider the gcd program, which handles integer (natural) variables x and y:
{int x; int y; //
1 read(x);
2 read(y);
3 while (x!=y)
216 STRUCTURAL CRITERIA
{if (x>y) //
5 {x=x-y;}
6 else
7 {y=y-x;}};
8 write(x);
The following table shows for each variable the statements in which the variable is defined, c-used, p-used, and terminated.
Line
Defined c-used p-used Terminated Defined c-used p-used Terminated 1 2 √
We can write the lifecycle of each variable as follows, by indicating the sequence of events that arose in the lifecycle, along with the lines where they did:
• Variable x: defined(2); p-used(4); p-used(5); c-used(6); defined(6); c-used(8); terminated(10). • Variable y: defined(3); p-used(4); p-used(5); c-used(6); c-used(8); defined(8); terminated(10).
If we observe a program in execution and focus on the sequence of events that take place during the lifecycle of any variable, we may find that some patterns are outright wrong, and some patterns, while they may be correct, look suspicious nevertheless, hence may deserve extra scrutiny. Among incorrect event sequences, we cite the following:
A variable that is used (use, c-use, p-use) before being defined (without being assigned a value). •
A variable that is used after its termination.
10.3 DATA FLOW COVERAGE 217
As for suspicious patterns, we cite the following instances: •
A variable that is defined twice in sequence without being used in the interven- ing time. •
A variable that is defined and then killed without being reused. These patterns do not necessarily indicate the presence of a fault, but they do
warrant careful consideration. For strictly sequential programs, it is possible for the compiler to detect incorrect patterns and suspicious patterns; but with control struc- tures such as if-then statements, if-then-else statements and loops, the compiler cannot predict execution sequences at compile time. The goal of data flow test generation criteria is to generate test data in such a way as to execute all the paths that may have incorrect or suspicious event sequences; we review a sample of these criteria in the following sections.