Weaving Aspects Into C++ Applications for Validation of Temporal Invariants
Total Page:16
File Type:pdf, Size:1020Kb
Weaving Aspects into C++ Applications for Validation of Temporal Invariants Tanton H. Gibbs and Brian A. Malloy Computer Science Department Clemson University Clemson, SC 29634, USA thgibbs, malloy @cs.clemson.edu f g Abstract [5]. During maintenance, invariants have proven invaluable for disclosing locations in the program In this paper, we describe temporal invariants, where the maintainer may have introduced a fault which are class invariants that are qualified by the [10]. operators eventually, always, never, or already. Tem- The problem with class invariants is that some poral invariants can capture assertions that may not important assertions about a class are initially in- be valid initially but, as the program continues, must valid, due to circular dependencies or the monoton- eventually become valid. Moreover, temporal invari- ically increasing nature of the system under con- ants can indicate references to memory that should struction [8]. For example, during compilation of eventually be deallocated. To facilitate incorporation a program, a name object is constructed to facil- of temporal invariants as a maintenance or reengi- itate name lookup. However, certain fields in the neering activity, we weave invariants into the sys- name object, such as the corresponding scope of the tem as aspects. In our case study of a C++ sys- name, may not be known until after name lookup tem, the aspects are woven into join points using has occurred [24]. Moreover, assertions about a policies. We investigate the effectiveness of tem- class may have an important impact on memory poral invariants and we compare the performance management. For example, some heap-based ob- of our aspect-oriented implementation with several jects of a class must be eventually deleted or system other approaches. performance will degrade, while others need not be deleted. Thus, assertions about class attributes may not be valid initially, but may have an important 1 Introduction impact on the system under construction. In this paper, we describe temporal invariants, A class invariant is a property that applies to all which are assertions about a class that are qualified instances of the class [22]. The majority of proper- by the operators eventually, always, never, or al- 1 ties that are established during verification of pro- ready . Temporal invariants can capture assertions grams are either invariants or depend crucially on that may not be valid initially but, as the program invariants [29]. Invariants have been exploited to continues, must eventually become valid. In addi- improve system robustness [23, 26] and to help de- tion, temporal invariants can indicate references to fine strategies for building reliable components [14]. memory that should eventually be deallocated. To Additionally, invariants have been used to improve facilitate incorporation of temporal invariants as a testability [26] or to complement testing to expose 1In this paper, we discuss two kinds of invariants: class additional faults [10]. Recently, class invariants have invariants and temporal invariants. Class invariants are tra- ditional invariants about class attributes; temporal invariants been exploited to improve the diagnosis scope, or the are described in this paper. When the meaning is clear, we distance between a faulty statement and the obser- simply refer to invariants. vation of the fault in the flow of control in a program Published in Conference on Software Maintenance & Reverse Engineering (CSMR'03), Benevento Italy, March 2003 NameOccurrence uses in <<subsystem>> builds search <<subsystem>> Program Processor Symbol Table Scanner Scope looks for returns Parser NameDeclaration Type name : String kind : Kind containedIn : Scope <<use>> <<enumeration>> Kind Figure 1. Keystone summary. The Program Processor subsystem, illustrated on the left, marshals information about a name in a NameOccurrence object and directs the search for a corresponding NameDeclaration in the Symbol Table subsystem, illustrated on the right. The Symbol Table is com- posed of class inheritance hierarchies for Scope and Type. We use temporal invariants to validate the Scope, Type and NameDeclaration class hierarchies. maintenance or reengineering activity, we weave as- aspect-oriented programming and in Section 2.2 we sertions into the system as aspects [16]. describe keystone [19, 24], the application in our case We present a case study of a C++ system where study. In Section 2.3 we review an approach to val- the aspects are woven into join points using policies idating class invariants at the end of program exe- [2]. Our case study includes an investigation of the cution [10]. effectiveness of temporal invariants and we compare the performance of our aspect-oriented implementa- 2.1 Aspect-Oriented programming tion with validation of class invariants at the end of the program [10], as well as validation of class invari- Aspect-oriented programming, AOP, extends the ants at the end of constructors, at the beginning of object-oriented paradigm by enabling more main- destructors and at the beginning and end of meth- tainable code using units of modularity called as- ods [8]. Our temporal invariants are expressed in the pects. Aspects encapsulate elements such as perfor- Object Constraint Language (OCL) [3], extended to mance optimization, error checking, exception han- accommodate temporal considerations [25]. dling, logging and debugging, which cut across tra- In the next section, we review terminology and ditional class or module boundaries. AOP uses an background that relates to our work and in Section aspect weaver to process the development and as- 3 we describe temporal invariants including some pect languages, composing the aspects at join points examples of their use. In Section 4 we describe our to produce the desired total system operation [16]. model of temporal invariants and our technique for weaving temporal invariants as aspects into the case 2.2 The keystone parser front-end study application. In Section 5 we provide some results of our study and in Section 6 we review some of the work that relates to temporal invariants. We Figure 1 summarizes the design of our case study draw conclusions in Section 7. application, keystone [19, 24], a parser and front-end for ISO C++ [13]. The figure presents two subsys- tems, illustrated as tabbed folders and designated 2 Background by the subsystem stereotype. The Program Pro- cessor subsystem is shown on the left and the Symbol In this section we provide background about ter- Table subsystem is shown on the right of Figure 1. minology and some of the systems and concepts that The Program Processor subsystem includes a Scan- we use in our paper. In the next section we review ner and Parser and is responsible for initiating and 2 contains directing symbol table construction and name lookup. NameDeclaration This responsibility includes two phases: (1) assem- bling the necessary information for creation of a Scope {abstract} NameOccurrence object, and (2) directing the search lookup(NameOccurrence*) for a corresponding NameDeclaration object in the containedIn Symbol Table subsystem. The Symbol Table subsys- tem is the symbol table in the parser, including class NamespaceScope LocalScope PrototypeScope hierarchies for type information, Type, and scope in- formation, Scope, shown on the right of Figure 1. uses The Symbol Table subsystem, the target of our val- FunctionScope ClassScope TemplateParameterScope idation effort, is discussed further in Section 3. <<instanceOf>> globalScope : NamespaceScope derivedFrom 2.3 Validating invariants at end of program (1) context Scope (2) inv: always( Reference [10] describes a non-invasive approach (3) self.getContainingScope() <> NULL xor for validation of class invariants in C++ applica- (4) self.getName() = ' GlobalNamespace') (5) inv: always( tions, where the invariants are specified using the (6) self.getLocals() forAll ( Object Constraint Language (OCL). The approach (7) n:NameDeclaration! j is fully automated so that the user need only sup- (8) n.getContainingScope() = self )) ply the class invariants for each class hierarchy to be (9) context TemplateParameterScope checked and a validator constructs an InvariantVis- (10) inv: eventually( itor, a variation of the Visitor pattern [2, 21], and (11) self.getLocals() forAll ( n:NameDeclaration (12) n.getType().oclIsKindOf(namespaceType)! an InvariantFacilitator. Instantiations of the Invari- j antVisitor and InvariantFacilitator classes encapsu- (13) = NULL)) late the invariants in C++ statements and facilitate the validation of the invariants at the end of program Figure 2. Temporal invariants. In this fig- execution. However, the technique in reference [10] ure, we illustrate some temporal invariants does not easily extend to validating invariants at ar- for the Scope & TemplateParameterScope bitrary points in a program. classes. 3 Temporal Invariants An always valid invariant is an assertion about In this section, we describe temporal invariants a class that must be valid at the end of a con- and compare them to class invariants. We then structor, at the beginning and end of all method present some examples of temporal invariants ex- invocations and at the beginning of a destructor. pressed in the Object Constraint Language (OCL) An always valid invariant is similar to a traditional [3], extended to accommodate temporal considera- class invariant except that always valid invariants tions [25]. are also checked at program termination. An even- tually valid invariant