Structural operational semantics as a basis for static program analysis

interpretation was defined originally in terms of flow charts or dynamic discrete systems [Cousot and Cousot 1977]. From the usual flow-chart operational semantics, a so-called static (or collecting) semantics is derived automatically by attaching to each program point (flow-chart arc) the set of contexts (states) that flow to that point during execution. The collecting semantics summarizes “what really happens at runtime,” and the goal of abstract semantics is to compute properties for the program points that describe the concrete context sets. The abstract semantics does this by executing the flowchart with abstract values that represent context properties. The preceding formulation is simple and effective, but flow charts have major weaknesses that preclude their use as a general framework for static program analysis: they are too low-level and they do not enjoy the compositionality property. A subsequent advance was the formulation of abstract interpretation in a compositional manner via denotational semantics definitions [Nielson 1982]: equationally represented flow charts were replaced by structurally recursive equations, and abstract value sets were formalized as Scott domains. These techniques were elegant, and they opened the door to analysis of higher-order programs [Burn et al. 1986], but there was a price to be paid: properties that are inherently intentional (i.e., involve relations between intermediate rewriting steps) cannot be naturally expressed in the extensional format used by denotational semantics. Permission to make digital /hard copy of part or all of this work for personal or classroom use is granted without fee provided that the copies are not made or distributed for profit or commercial advantage, the copyright notice, the title of the publication, and its date appear, and notice is given that copying is by permission of the ACM, Inc. To copy otherwise, to republish, to post on servers, or to redistribute to lists, requires prior specific permission and / or a fee. © 1996 ACM 0360-0300/96/0600–0340 $03.50 ACM Computing Surveys, Vol. 28, No. 2, June 1996 This has a negative impact on the collecting semantics, which no longer can be derived automatically from the concrete semantics but must be written from the concrete semantics by adding “occurrence” arguments, which label program points, and “storage caches,” which are additional state arguments that gather and save intentional information. Consequently, we are obligated to prove that the collecting semantics is correct with respect to the concrete semantics, but it is unclear how one proves that the intentional information gathered by the collecting semantics is correct with respect to a concrete semantics that possesses no notion of intention. In addition, the denotational semantics style sometimes move the static analysis too far away from its intended application. As an illustration, Burn and Le Métayer [1996] consider the use of continuations to prove the correctness of strictness-based optimizations. A continuation is basically a functional representation of the control flow that is otherwise left implicit in a denotational semantics. The correctness proof of the static analysis is far from trivial, and one reason is that an essentially operational property (neededness) is recast in the denotational framework (strictness) for the sake of the analysis, then to be used in an operational framework (abstract machine or compiler). ANALYSIS BASED ON STRUCTURAL OPERATIONAL SEMANTICS We believe that a formal framework for the definition of static program analyses should enjoy the following properties. —It must ease the formal specification of the analysis (the property of interest) and keep it separate from the algorithmic issues involved (i.e., how the property is computed by the analyzer). —It must provide a useful basis for the design of new analyzers and the reuse of a set of common underlying tools. The two main approaches to formal semantics are operational semantics and denotational semantics. We have argued in the introduction that neither flow charts nor denotational semantics is satisfactory with respect to the preceding criteria. As a result, we propose structural operational semantics for our framework. The main virtue of SOS, introduced in Plotkin [1981], is that it is both structural (compositional) and intentional. It is structural because a program makes a computation step if and only if a phrase within the program can make the step, and it is intentional because the derivation tree that is drawn to take a computation step contains all the intermediate relationships that generated the step. The SOS framework can define the semantics of various classes of languages (including nondeterministic and concurrent languages) and thus forms a solid basis for the design of a program analysis platform. Significantly, an SOS does not need rewriting into a collecting semantics to gather the intentional information that is required for most useful program analyses. The reason, noted previously, is that the semantics associated with a program is not merely the value returned by the program but the whole derivation tree(s). Static analyses can then be specified by defining the properties of interest as abstractions of these derivation trees. As an illustration, the fact that two variables x and y in an expression e must be accessed in a specific order to compute the value of e can be expressed as a property of derivation trees with e as the expression at the root. Last but not least, the relationship between the concrete semantics and the abstract semantics can still be defined by a Galois connection (relating concrete derivation trees to abstract derivation tress), which makes it possible to rely on the fundamental results of abstract interpretation. Structural Operational Semantics • 341 ACM Computing Surveys, Vol. 28, No. 2, June 1996 STATE OF THE ART AND PERSPECTIVES The original definition of SOS [Plotkin 1981] was limited to finite proof trees. It has been shown that this limitation can be lifted [Cousot and Cousot 1992; Schmidt 1995] using a combination of positive and negative inductive definitions. This leads to a specification method in which finite and infinite behavior can be defined in a uniform way and the denotational semantics itself can then be seen as an abstraction of the structural operational semantics [Cousot and Cousot 1992]. The use of operational semantics as a basis for static analysis has been advocated recently in a number of papers [Cousot and Cousot 1992; Schmidt 1995]. For instance, Schmidt [1995] specifies a functional language using a variation of SOS called natural semantics (or “big-step operational semantics,” because it defines a relation between an expression and its normal form without considering intermediate steps, as opposed to “small-step SOS” [Nielson and Nielson 1992]). Among the challenging problems for future research, let us mention: —The application of the methodology suggested in this article to other programming styles (imperative programming, parallel programming, logic programming, . . .). A number of analyses proposed for imperative languages (data flow and control flow analyses, alias analyses) have been designed with efficiency considerations in mind and correctness issues have often been neglected. SOS-based analyses should help reconcile both objectives [Schmidt 1995]. —The study of analyses based on smallstep SOS and the relationship between small-step and big-step SOS with respect to static analysis. Natural semantics is a more natural basis for the definition of a static analysis because it is suited to proofs by structural induction on derivation trees (when small-step SOS leads to proofs by induction on the length of derivation sequences), but small-step SOS is more precise and it is required for a proper treatment of nondeterminism, nontermination, and parallelism [Nielson and Nielson 1992]. —The design of a platform supporting the development of new analyzers from a specification of the SOS of the language and the property of interest. Several efforts have been reported for the design of generic analyses that are not based on operational semantics [Venkatesh 1989; Yi and Harrison 1993]. Genericity is achieved by parameterizing the abstract domains and choosing appropriate abstract functions. We believe that a platform based on a SOS would be a better vehicle for a clear separation between the logical and the algorithmic concerns and would favor the reuse of common underlying tools (such as fixpoint engines) for a wider class of languages. As a conclusion, we believe that the study of SOS-based static analysis is a promising research direction from both theoretical and practical perspectives.