Contingent Faults
6.3.1 Contingent Faults
Now that we have defined the concept of relative correctness, whereby a program can be considered more-correct than another (in a way: getting closer to a correct program), we are ready to define a fault. A fault may be localized at an arbitrary level of granularity: at the level of a line of code, or at the level of a simple state- ment (e.g., assignment statement and condition), or the level of a compound state- ment (sequence, if-then, if-then-else, while-loop), or the level of a block (unnamed block, with variable declarations and executable statements, or named block, such as a function body), and so on. We want to define faults in such a way that the definition applies equally to any scale of granularity. Hence in general, we view a program as an aggregate of components linked by programming constructs; the size of these components determines, for our purposes, the level of granularity at which we want to localize faults in a program. As an example, we consider the following program:
#include <iostream> … … … // line 1 void count (charq[]) {int let, dig, other, I, l; char c; //
2 i=o; let=0; dig=0; other=0; l=strlen(q); /* init */ //
3 while (i<l) {
4 c=q[i];
/* t */ //
5 if (‘A’≤c && ‘Z’>c) let=+2;
7 if (‘a’≤c && ‘z’≥c) let=+1;
9 if (‘0’≤c && ‘9’≥c) dig=+1;
/* c3, b3 */ // 10 else
// 11 other+=1;
/* b4 */ // 12 i++;}
/* inc */ // 13 printf(“%d %d %d\n”, let, dig, other);} /* print */ // 14
108 FAILURES, ERRORS, AND FAULTS
Using the abbreviations given in the comments (between /* and */), we can rewrite this program as follows:
{init; While(t) {b0; if (c1) {b1} else if (c2) {b2} else if (c3) {b3} else b4; inc}; Print;}
We can rewrite this program at a finer grain (by decomposing conditions into their conjuncts, for example) or at a coarser grain (by coalescing statements into larger blocks), depending on the precision with which we wish to identify/localize faults. The definition of a fault, which we give below, is based on two assumptions:
1. First, we are not questioning the structure of the program; rather we are only questioning the correctness of each part thereof. If we feel that the structure may be at fault, then we need to rewrite the program at a coarser level of granularity.
2. Second, the designation of a particular program part as faulty is somewhat dis- cretionary: we are assuming for a moment that other components are not in question and pondering whether modifying the selected component will make the program more-correct. This explains why we refer to these faults as contin- gent faults: They are faulty if we assume for the time being that other parts are not; also once the designated fault is corrected, the existence, number, location, and nature of other faults may change.
Whence the following definition. Definition: Contingent Fault We let R be a specification on space S and we let p
be a program on space S, which is written at some level of granularity as p=Cp 1 ,p 2 ,p 3 ,…, p i ,…, p n . We say that p i is a contingent fault (or simply a fault) in program p with respect to specification R if and only if there exists a program component p i such that the program p defined by p = C p 1 ,p 2 ,p 3 ,…,p i ,…,p n is strictly-more-correct with respect to R than p.
Note that we require that p be strictly-more-correct than p; it is not sufficient that it
be merely more-correct. The reason for this requirement is that if we accepted that p
be more-correct than p, then any statement of p will be considered a fault—of course we do not want that; we want to consider as faults statements whose modification leads to an effective increase in the competence domain of the program.
As an illustration, we consider the program above and investigate its faults with respect to the following specification:
R= s,s q list char os = os # A q # 0 q # # q,
6.3 CONTINGENT FAULTS AND DEFINITE FAULTS 109
where: • os designates the output stream of the program (declared by the #inclu-
de<iostream> statement), •
represents concatenation, • # A (q), # 0 (q), # # (q) designate, respectively, the number of alphabetic characters, numeric characters, and special symbols in array q.
We argue b1 is a fault in p with respect to R; to this effect, we must offer an alternative statements b1 that makes the set dom R P larger. We propose b1 = (let+=1;) and we show that this yields a more-correct program. We find,
dom R P = s q list char CHAR ,
where CHAR represents the set of upper case alphabetical characters. Indeed, this pro- gram works correctly with respect to R as long as the input sequence does not include any upper case letters: all upper case letters from “A” to “Y” are counted twice in let, and “Z” is counted as a special character (variable other) rather an alphabetical char- acter (let). As for program p , which is obtained by changing b1 into b1 , we find
dom R P = s q list char Z Indeed, now the program counts the number of all upper case letters properly,
except for “Z”; as it is written, the program counts occurrences of “Z” as special char- acters (variable others), rather than alphabetical characters (variable let). Clearly, we do have
dom R P
dom R P ,
hence p is strictly-more-correct than p and hence b1 is a contingent fault.