Program Slicing Based on Specification I. S. Chung
W. K. Lee
G. S. Yoon, Y. R. Kwon
School of Information and Computer Engineering Hansung University 389, 2-ga Samsun-dong, Sungbuk-gu, Seoul 136-792 Korea
School of Electrical, Electronics,& Computer Engineering Jeonju University Hyoja 3ga 1200, Jeonju, 560-759, Korea
Department of Electrical Engineering & Computer Science KAIST 373-1, Kusong-dong, Yusong-gu, Taejon 305-701, Korea
[email protected]
[email protected]
[email protected]
Keywords Program Slice, Software Reuse, Software Maintenance, Weakest Precondition, Strongest Postcondition,
ABSTRACT Slicing techniques can provide solutions to many software engineering problems such as testing, program understanding and extraction of a reusable component. However, current slicing criteria and the corresponding techniques might obtain slices that contain unnecessary statements in some situations. In this paper, we propose a new slicing technique that takes the specification of the slice into account. The information present in the specification helps to produce more precise slices by removing statements that are not relevant to the specification for the slice. Our technique is based on the weakest precondition and strongest postcondition. We present an example of applying the proposed technique in extracting a reusable component from an existing program.
1.
INTRODUCTION
The concept of a program slice has been used to solve many software engineering problems since it was introduced by Weiser [11]. It is useful in debugging, testing, differencing, integration, tuning compilers, program understanding and maintenance [9]. A program slice is taken with respect to a slicing criterion (p; V ), where p is a program location and V is a subset of the program’s variables. Consequently, slices consist of statements which directly or indirectly affect the values of variables at the slicing criterion[11]. However, though this kind of slice preserves the behavior of the original program with respect to (p; V ), it often contains non-essential statements that can be sliced off when the slicing criterion is strengthen with more information about the context of applying the slicing technique.
Consider a situation in which one wants to recover reusable components from existing software satisfying a specification. One possible approach that adopts the concept of slicing is to build a slicing criterion in such a way that V contains all output variables used in the specification. Even though this approach allows one to get a smaller program than the original program with the same behavior with respect to V , the extracted component could be unnecessarily large. This unnecessarily bulky slice is due to the fact that the chosen slicing criterion and corresponding slicing technique considers only syntactic dependency ignoring the semantic information present in the specification. In order to address this problem, it is necessary to utilize all the information available by considering the relation between the specification and semantics of the program, not only the syntax. For this purpose, we define a slicing criterion as C = Spec, where the Spec is a pre-postcondition pair (P; Q). Precondition P is a predicate on the input variables, describing assumption about the input values. Postcondition Q is a predicate on the input and output variables, representing the desired behavior of the slice. With the new slicing criterion, we define specification based slicing rules using well-known weakest precondition, and strongest postcondition concepts. Our study on specification based slicing is motivated from refinement calculus [1] which gives a set of rules for deriving concrete programs from their specifications. One of the important results of refinement calculus can be stated: for programs S1 and S2 , S1 is reP [S2 ]Q holds for any pre-postcondition fined by S2 if P [S1 ]Q pair (P; Q). This implies that we can replace any occurrence of S1 by S2 . Program S2 is constructed from S1 by applying a set of refinement rules, which is designed to introduce a particular feature into a final program. Not surprisingly, we are able to treat specification based slicing in terms of the refinement semantics. The objective of slicing program S2 is to produce a smaller program S1 from S2 in such a way that S1 shows the same behavior as S2 with respect to the specific pre-postcondition (P; Q) by deleting zero or more statements from S2 1 . This can be phrased in terms of the P [S1 ]Q refinement relation between S1 and S2 : P [S2 ]Q
)
)
Both refinement calculus and specification based slicing deal with transformation of a program into another programs while preserving the correctness. However, while the refinement calculus deals with a process that aims to produce more concrete programs from 1 Technically speaking, the statements are replaced with skips which mean do nothing, not removed from the program.
an abstract one, specification based slicing produces more specialized programs from a concrete program. The rest of this paper is organized as follows: we briefly review the concept of the weakest precondition and strongest postcondition, and then present a simple programming language used through out this paper in Section 2. In Section 3, the detailed definitions and the characteristics of the specification based slice are given. We also present an example application of the new slicing technique in extracting a reusable component. In Section 4, we relate the specification based slicing with other researches. We give some concluding remarks and further research directions in Section 5.
2.
PRELIMINARIES
f
A state of a program is defined as (var0 ; val0 ); (var1 ; val2 ); : : : , where vari is a program variable and vali is the value of the corresponding variable. Let S be a program and P; Q be the predicates on program states. The weakest precondition wp(S; Q) is a predicate representing the program states which guarantees the program termination and satisfaction of Q after the program terminates, whenever the program starts execution in that states.
g
The strongest postcondition sp(S; P ) is a predicate representing the final program states that occur after the execution when the program started execution in states satisfying P . Thus it is forward. The strongest postcondition is liberal in that it assumes that the program terminates. We will apply the concepts of weakest preconditions and strongest postconditions to the following simple programming language. Although the language is simple, it has all the essential features of a programming language.
S::=
skip (do nothing) abort (abnormal program termination) < variable >:=< expression > (assignment) S1 ; S2 (sequential composition) if B then S1 else S2 fi (conditional composition) do B S od (repetition)
j j j j j
Here, B is a Boolean expression, S1 , S2 , S are statements. For the detailed descriptions of the definitions of the weakest precondition and the strongest postconditions for this language, refer to the literature [4, 1, 5, 6].
3.
FORMAL DEFINITIONS OF SPECIFICATION BASED SLICING
Before we define the specification based slice with respect to a specification (P; Q), we first introduce two special forms of the specification based slices; a precondition based slice and a postcondition based slice. A precondition based slice is a specification based slice in which only a precondition is considered. A precondition based slice of a program S identifies a subset of statements that are influenced by P . Similarly, a postcondition based slice is a specification based slice that ignores a precondition. It constructs a slice by identifying statements that influence Q.
3.1 Precondition Based Slicing
A precondition based slice with respect to a precondition P is a forward static slice that consists of a subset of the statements and control predicates of a program that might be executed and change the program state when the program start execution in a state satisfying P . A program Si is said to be a portion of Sj if Si can be obtained from Sj by deleting zero or more statements from Sj , denoted by Si Sj .
D EFINITION 1 ((P; ) Slice). Given two programs S1 and S2 , program S1 is a slice of S2 with respect to P, denoted by S1 (P;) S2 , if and only if sp(S1 ; P ) sp(S2 ; P ), S1 S2 , and P ) wp(S2 ; true).
A (P; ) slice is a precondition based slice that preserves the program’s behavior for initial states satisfying the precondition P . There can be many different precondition based slices for a given precondition, and there is always at least one such a slice if the precondition P implies that S terminates: the entire program itself.
Consider a simple program “if (i 5) then n := n+i else n := 10 fi”. Assume that the specification is given as an precondition, P = “(n = i 10)”, where is any integer value. A conventional forward slice of this program with respect to the given specification2 is the program itself. Nothing can be sliced away because all of the statements have dependencies to the given slicing criterion. On the other hand, in the case of precondition based slicing, the else part can be changed to skip because the else part is never executed if the statement is executed in a state satisfying P . In this simple example, we can find that a statement may be sometimes deleted even though it assigns a value to a variable appearing in the precondition.
^
RULE 1. If Si is an assignment statement and sp(Si ; p) then
p
[skip=fSi g] (P;) :
f gf g
, where [ Si = S j ] represents a program that is same to except that statement S j is replaced by Si . RULE 2. If Si is a conditional statement of the form if B then Si;1 else Si;2 fi and p B then
[Si;2
): =fS g]
:
(P; )
i
And the similar argument holds for Si;1 when p
) B.
RULE 3. If Si is a repetition statement of the form do B S od wp( do B S od ; true), then and sp(S; B p) p and p
^
[skip
) f =fS g]
g
(P; )
i
:
4. If S ; ; S ; S ; ; S 2 and sp( S ; p for some i m, then [ =fS ; ; S g] :
RULE ; Si ; p)
1
1
i
skip
1
i
1
m
i
(P; )
Figure 1: Precondition Based Slicing
f g
2 we assume that the slicing criterion is (if statement, n,i ) which is derived in a way that was explained in Section 1.
Figure 1 3 shows the rules to compute precondition based slice for a given precondition. Rule 1 states that when an assignment statement does not change the program state, then the assignment can be replaced by skip. In the substitution, we will assume that statements are uniquely labeled. This assumption allows substitution is performed without any confusion about which statements should be replaced although there may be more than one syntactically identical statements. Rule 2 shows the case of a conditional statement. If it is true that one of the two branches will not be executed whenever the program is executed in a state satisfying P , the entire conditional statement can be replaced by the other branch. For an n-ary conditional statement, Rule 2 would just replace the corresponding branch statement with skip. Rule 3 states that if p is not changed by the repetition body S and p implies termination of the repetition statement, then the repetition statement can be eliminated. Note that the given precondition is a loop invariant that holds before and after S . Precondition based slicing of a repetition statement can be easily done under certain conditions. For example, if the Boolean expression initially evaluates to false for the given precondition P , i.e., P B , the loop body S is never executed. Thus, we can assure that slicing the repetition statement off does not affect the behavior of the unmodified program.
):
D EFINITION 2 ((; Q) Slice). Given two programs S1 and S2 , a program S1 is a slice of S2 with respect to Q, denoted by S1 (;Q) S2 , if and only if wp(S1 ; Q) wp(S2 ; Q) and S1 S2 .
A ( ; Q) Slice S1 is a postcondition based slice of program S2 if S1 and S2 exhibit the same behavior with respect to predicate Q that is given as a postcondition. Of course, S1 consists of a subset of statements and control predicates of S2 . RULE 5. If Si is an assignment statement and wp(Si ; q ) then
q,
[skip=fSi g] (;Q) RULE 6. If Si is a conditional statement of the form wp(Si;1 ; q ) q , then if B then Si;1 else Si;2 fi and B
[skip=fSi;1
) g] (
;Q)
:
And the similar argument holds for Si;2 when wp(Si;2 ; q ) q .
:B )
RULE 7. If Si is a repetition statement of the form do B S od and B wp(Si ; q ) B q and q wp(Si ; true), then
^
^
[skip
) =fS g] (
i
;Q)
:
8. If S ; ;S ; S ; ;S 2 q for some i > 0, then [ =fS ; ; S g]
and wp(Si ;
For a more precise slice, it is necessary to consider the propagation effects on a given precondition that can happen due to a sequential composition of statements in addition to previous rules. Consider the case where we want to obtain a precondition based slice of the program of the form “x := x 1; x := x + 1” with respect to a precondition P =“(x 0)00 . From the rules of calculating strongest postconditions, the strongest postcondition of the statement S1 , “sp(S1 ; P )”, becomes the precondition of the statement S2 . It is immediate that “P = sp(S1 ; P )” and “sp(S1 ; P ) = sp(S2 ; sp(S1 ; P ))”. From Rule 1, none of the two statements are eliminated. Obviously, this result is not satisfactory because P is equivalent to “sp(S2 ; sp(S1 ; P )) = (x 0)”. This is because the sequential composition of the two statements has cancelled out the effects on the given precondition P . Rule 4 states this case.
Rule 6 4 states that if a branch of if statement does not affect the weakest precondition, then the branch can be replaced by a skip. By Rule 7, if the given postcondition is a loop invariant and it is ensured that the loop terminates, then the loop itself can be sliced. Additionally, we need a rule for the sequential composition of statements as in the case of the precondition based slicing, which is shown in Rule 8.
3.2 Postcondition Based Slicing
3.3 Computing Specification Based Slices
RULE ; Sm ; q )
skip
6
6
A postcondition based slice with respect to a postcondition Q is a backward static slice that consists of a subset of the statements and control predicates of a program that might affect the postcondition Q when the program is executed. Comuzzi and Hart proposed a slicing technique called “p-Slice”[3]. p-Slice is based on the weakest precondition, and it satisfies the requirement for the definition of a postcondition based slice. We will adopt their arguments in this paper. However, for the uniform presentation, we will refer a p-Slice as a postcondition based slice. In the following, we will summarize the results of [3] without any detailed illustrations. 3 For the following discussion, let us assume that is a program consisting of statements from our simple language of Section 2, Si , and p is the precondition for Si derived from P by the sp predicate transformer [4]. And further assume that the original program is correct with respect to the specification (P; Q), that is, P wp(; Q).
2
)
1
i
i
1
i
m
m
(
;Q)
:
Figure 2: Postcondition Based Slicing
Basically, a program S1 is a specification based slice of S2 with respect to the given pre-postcondition pair (P; Q) if S1 preserves the correctness of S2 for (P; Q) and S1 can be obtained from S2 : If S2 satisfies the given specification (P; Q), then S1 , which has been obtained from S2 by deleting zero or more statements, also satisfies the specification.
D EFINITION 3 ((P; Q) Slice). Given two programs S1 and S2 , program S1 is a slice of S2 with respect to C = (P; Q), wp(S2 ; Q)) denoted by S1 (P;Q) S2 , if and only if (P (P wp(S1 ; Q)) and S1 S2 .
)
)
)
4 For the following discussion, let us assume that is a program consisting of statements from our simple language of Section 2, Si , and q is the postcondition for Si derived from Q by the wp predicate transformer [4]. And further assume that the original program is correct with respect to the specification (P; Q), that is, P wp(; Q).
2
)
It is clear from Definition 3 that (P; Q) Slice relation is reflexive and transitive. Furthermore, if program S1 is a slice of program S2 , then, for the initial state that satisfies P , 1. if the execution of S2 in this initial state is guaranteed to terminate, then the execution of S1 in this initial state is also guaranteed to terminate, and
Q : q0
absmax = a b _ absmax = b a
(2)
To compute a precondition based slice, we apply the precondition based slicing rules of Figure 1 to codes shown in Figure 36 . Figure 4 shows the obtained precondition slice where no more statements can be deleted with respect to P . We can easily check that the precondition based slice satisfies the specification (P; Q).
2. postcondition Q, which holds for the final states of an execution of S2 , is also satisfied by an execution of S1 .
3 4 5 6 7 8 9
Theorems 1 and 2 can be derived from Definition 3 and above properties 5 . They show that obvious ways to compute specification based slices are to construct either precondition based slices or postcondition based slices.
if a>b then absmax absmin else absmax absmin fi
:= a; := b := b; := a
Figure 4: A Precondition Based Slice T HEOREM 1. If S1
S2 , then S1 (P;Q) S2 .
T HEOREM 2. If S1
S2 , then S1 (P;Q) S2 .
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
(P; )
(
;Q)
On the other hand, a specification based slice can be also computed, according to Theorem 2, by constructing a postcondition based slice with respect to Q. Figure 5 shows the result of postcondition based slicing. We can also check that the postcondition based slice satisfies the specification (P; Q), too. 1 2 3 4 6 7 9 10 11 12 14 15 17 18 19 20 22
if (a>0 and b>0) or (ab then absmax := a; absmin := b else absmax := b; absmin := a fi else if a>b then absmax := -b; absmin := -a else absmax := -a; absmin := -b fi fi else absmax := 0; absmin := 0 fi
Figure 5: A Postcondition Based Slice
Figure 3: An Absolute Min/Max Program As an example, let us consider the following absolute minimum and absolute maximum problem.
“Given two input, compute the absolute minimum and absolute maximum. When the inputs are of the same sign, the absolute minimum should have the value of input with the smaller absolute value and the absolute maximum should have the value of input with the larger absolute value. Otherwise, it is meaningless to compare inputs. Accordingly, both of the outputs should be 0.”
a>0^b>0
However, even though Figure 4 and 5 are valid specification based slices, a more precise slice can be obtained. Note that Theorem 1 does not utilize the postcondition while obtaining the specification based slice and Theorem 2 does not utilize the precondition. More precise slice can be obtained by using the information of precondition and postcondition at the same time. The transitiveness of the specification based slices and Theorems1 and 2 provide the soundness of the following theorems which are the foundations of the methods to compute precise specification based slices. T HEOREM 3. If S2 (P;) S3 and S1 (;Q) S2 , then S1 (P;Q) S3 .
The program listed in Figure 3 computes the absolute minimum and absolute maximum according to the above problem statements. Now, suppose that we want to extract a reusable component from the program shown in Figure 3 that finds out maximum out of two positive numbers. This new specification can be formulated as:
P : p0
if (a>0 and b>0) or (ab then absmax := a else absmax := b fi else if a>b then absmax := -b else absmax := -a fi fi else absmax := 0 fi
(1)
5 Due to space limitation, all proofs are omitted. An extended version of the paper can be obtained by contacting the authors.
T HEOREM 4. If S2 (;Q) S3 and S1 (P;) S2 , then S1 (P;Q) S3 . Theorem 3 and 4 guide us how to obtain a specification based slice of a given program with respect to a specification (P; Q) by applying the precondition based slicing and the postcondition based slicing in sequel or by applying the postcondition based slicing first and then applying the precondition based slicing. 6 Due to space limitation, we omit the detailed steps of applying the slicing rules.
Theorem 3 states that we can get a specification based slice by applying the postcondition based slicing to the precondition based slice of Figure 4. The final slice is shown in Figure 6. It is obvious that produced slice satisfies the specification (P; Q).
3 4 6 7 9
if a>b then absmax := a else absmax := b fi
Figure 6: More Precise Slice of the Example Program Theorem 4 also states that a specification based slice of example program can be obtained by applying the postcondition based slicing to the precondition based slice of Figure 5. Figure 6 shows the final slice. Note that though this approach is different from the previous one in the sequence of applying two slicing techniques, they produce the same result. Informally speaking, this can be explained by the fact that the statements of final resultant slice are only those statements relevant to the specification (P; Q).
4.
RELATED WORK
Static slicing and dynamic slicing provide the basis for many different definitions of slicing proposed in the literature. The difference between static and dynamic slicing is that dynamic slicing assumes a fixed input for a program, whereas static slicing does not make assumptions regarding the input [7, 8]. A dynamic slicing criterion specifies the input, and distinguishes between different occurrences of a statement in the execution history. The availability of run-time information makes dynamic slices smaller than static slices, but limits their applicability to that particular input. We can also express a dynamic slicing criterion in terms of a specification based slicing criterion if dynamic slices are computed with respect to the last statement of the program. For example, suppose that we are given a program S with two input variables, in1 and in2 and one output variable out. Then, we want to construct a dynamic slice consisting of the statements that actually affect the value of the output variable out at the last statement of the program for input values of in1 = 3 and in2 = 0. We can compute the same slice by applying specification based slicing with respect to the slicing criterion C = (in1 = 3 in2 = 0; sum = ), where is any integer value. This means that specification based slicing provides a more general framework than dynamic slicing even though specification based slicing requires intensive human interaction. The cost of specification based slicing can be reduced if tools such as theorem provers can be adopted in computing the slice.
^
Quasi-static slicing is a typical slicing definition that falls between static slicing and dynamic slicing [10]. A quasi-static slice consists of the statements that affect the value of the variable at a program point when some inputs are fixed while other input values vary. If all input values are fixed, quasi-static slicing reduces to dynamic slicing. We can also observe that quasi-static slicing coincides with static slicing when all input values vary. As in the case of dynamic slicing, a quasi-static slice can be constructed through specification based slicing. For example, let us consider a program S . For the program P , suppose that we want to extract a quasi-static slice which preserves the behavior of S on the output variable out when only one of the input variables are fixed, i.e., in1 = 5. Indeed, the resulting quasi-static slice is a specification based slice with respect to the slicing criterion C = (in1 = 5; sum = ).
Another interesting slicing definitions has been introduced in the literature, called conditioned slicing[2]. Conditioned slicing is very similar to specification based slicing. Conditioned slicing needs a specification which specifies the condition on the input, resulting the reduced program where the conditioned slice is computed. Conditioned slices can be mapped to precondition based slices. However, conditioned slicing does not consider the postcondition which specifies the desirable states which the slice should meet.
5. FUTURE WORK Although our research on specification based slicing offers improvements on the weak sides of the traditional slicing techniques, there are some issues that are worth of further research in theoretical aspects. We need to further identify other variants of the specification based slices, their characteristics and the relations between various definitions. Specifically, we need to generalize our definition of the specification based slice by removing the assumption that P wp(; Q).
)
Yet another important research area is the application of the specification based slice to other fields of software engineering. We have focused the application of the slice to software reuse in this paper. However, the notion of program slicing has been used in many application domains. We need to experiment with other applications such as testing, integration, and program understanding.
6. ACKNOWLEDGMENTS This work was supported by Korea Research Foundation Grant( KRF-99-E00280 ).
7. REFERENCES [1] R. J. R. Back, “A Calculus of Refinements for Program Derivations,” Acta Informatica, vol. 25, pp. 593-624, 1998. [2] G. Canfora, A. Cimitile, A. De Lucia, and G. A. Di Lucca, “Software Salvaging based on Conditions,” In Proceedings of International Conference on Software Maintenance, pp. 424-433, 1994. [3] J. J. Comuzzi and J. M. Hart, “Program Slicing Using Weakest Preconditions,” In FME’96 , vol. 1051 of Lecture Notes in Computer Science , pp. 557-575, Mar. 1996. [4] J. de Bakker, Mathematical Theory of Program Correctness, Prentice/Hall Int’l. Inc., 1980. [5] E. W. Dijkstra, “Guarded Commands, Nondeterminacy and Formal Derivation of Programs,” Communications of the ACM, vol. 18, no. 8, pp. 453-457, Aug. 1975. [6] D. Gries, The Science of Programming, Springer-Verlag New York Inc., 1981. [7] B. Korel and J. Laski, “Dynamic Program Slicing,” Information Processing Letters, vol. 29, no. 3, pp. 155-163, 1988. [8] B. Korel and J. Laski, “Dynamic Slicing of Computer Programs,” Journal of Systems and Software, vol. 13 pp. 187-195, 1990. [9] F. Tip, “A Survey of Program Slicing Techniques,” TR CS-R9438, Univ. of Amsterdam, 1994. [10] G. Venkatesh, “The Semantic Approach to Program Slicing,” In Proc. of the ACM SIGPLAN91 Conf. on Programming Languages Design and Implementation, Toronto, Ontario, pp. 26-28, June 1991. [11] M. Weiser, “Program Slicing,” IEEE Trans. on Software Engineering, vol. 10, no. 4, pp. 352-357, July 1984.