Load time verification and runtime monitoring would both be possible. Runtime ..... Component-Based Development: From Buzz to Spark. Computer, July. 1999.
Common Runtime Support for Assertions Nam Tran, Christine Mingins, David Abramson School of Computer Science and Software Engineering Monash University 900 Dandenong Rd, Caulfield East VIC 3145, Australia {nam.tran, cmingins, davida}@csse.monash.edu.au Abstract: Behavioural specifications in interface contracts are important measures for improving quality of software components. Common support for assertions as first class constructs in binary components and at runtime provides many benefits for better contracts specification and monitoring. Behavioural specifications in the spirit of Design by Contract can accompany binary components and be available at runtime to enable flexible and correct treatment, in a source language neutral manner. Load time verification and runtime monitoring would both be possible. Runtime monitoring is correct with regards to sub-typing and dynamic binding, and with sensible exception handling. Such a common support mechanism would also provide opportunities for richer specification techniques to help deal with difficult issues such as object re-entrance.
1 Introduction It is now widely recognised that component quality is a key factor for ensuring the success of component based software [16, 17, 18, 24, 25]. Among the key challenges for achieving high quality components is the need for better specification of component interfaces. In a component-based system, the constituent components are usually developed independently, possibly in different programming languages, interacting with one another through interfaces only [1, 25]. A component interface specification is seen as a contract between the component and its environment, specifying what the component provides its clients and what it requires from the environment in which it executes [1, 13, 24, 25]. As a result, an interface specification of a component’s observable functional and non-functional behaviours should be more complete and precise. To be complete and precise, a contract needs to specify both functional and non-functional aspects, such as functional operations annotated with pre- and post-conditions, safety and progress properties, and space and time properties, of the component [25]. These can map to four levels of contracts, namely basic contracts, behavioural contracts, synchronisation contracts, and quality of service contracts [3]. The term behavioural contract is commonly used to refer to interface specifications of functional operations including invariants, pre- and post-conditions. The Design by ContractTM (DbC) method introduced with the Eiffel language [14] enables class invariants, method pre- and post-conditions, loop variants and invariants to be written in the source and monitored at runtime. DbC goes a long way toward having better behavioural specifications. DbC has also been added to other programming languages such as Java [2, 4, 5, 9, 10, 11, 12] and C++ [8], and design language [20]. As noted above, constituent components of a component-based system may be written in different programming languages. The ability to mix languages is an important enabling factor for a successful component software industry as it allows for the utilisation of reusable libraries regardless of language of origin [15]. It also enables developers to leverage their skills in different languages. Indeed, most component models, including COM, CORBA, the Common Language Infrastructure (CLI) platform [6], and the Web services paradigm [7, 22], are inherently multilanguage. It is our view that a common mechanism to support general assertions and DbC for binary components, neutral of source programming languages and assertion notations, would go further toward having better contracts for software components.
We choose to realize our ideas in the CLI as it is a multi-language component platform with a major commercial implementation (Microsoft’s .NET) and a number of open source implementations (Microsoft’s Rotor, Ximian’s Mono, and DotGNU’s Portable.NET). The remainder of this position paper is organised as follows. Section 2 describes our proposed common mechanism for supporting general assertions and DbC, along with the benefits of such a mechanism. Section 3 sketches an implementation of that mechanism in the CLI as a work in progress.
2 Common support for general assertions and DbC In this work, we propose the use of a common binary representation format for representing assertions, DbC constructs, and a runtime assertion support service, as shown in figure 1. The common representation format is an extension to the binary format of executable components. In our implementation, we plan to extend the CLI portable executable format to include assertions and DbC constructs. The binary format extension allows compiled assertions and DbC constructs to be stored in the components, but separately from the bodies of methods. That means compiled representations of class invariants, method pre-conditions, method post-conditions, are not merged into the bodies of the methods in question [2, 4, 8, 10], or used in auxiliary methods [5, 9]. Instead, they are linked with program methods (through metadata in the CLI) but remain separate as first class entities in the binary components. This is fundamentally different from existing approaches to supporting assertions and DbC. Most existing mechanisms referenced above instrument code by either inserting extra code into method bodies or generating wrapper methods. The runtime assertion support service will handle retrieving of assertions and DbC constructs information from binary components, enables runtime monitoring and reflection, or pre-runtime verification. Because the assertions and DbC constructs are first class entities in the components, they can easily be retrieved and manipulated. The runtime service retrieves this information, creates equivalent runtime constructs to enable proper monitoring and even reflection. The runtime monitoring activities can be controlled by fine grained and flexible policies via configuration information. The runtime service checks the policies, performs invariants, pre-conditions and postcondition checking as required, raising exceptions if appropriate. We will also extend the reflection facility to work with the new metadata. Reflection as supported by the CLI [6] and Java [23] is useful as it enables meta-programming and facilitates dynamic, late binding. In these platforms, the binary components contain type information. The reflection APIs allow programs to retrieve such type information and create corresponding objects at runtime. With our planned extension of the reflection facility, programs can also retrieve assertions and DbC constructs from binary components. This would enable a class of verification tools that perform their checks before running a component, perhaps at composition time or load time. Dynamic contract adaptation in the spirit of parameterised contracts [21] might also be possible. This scheme for supporting assertions and DbC has a number of advantages over existing mechanisms. Firstly, components written in any source language with any assertion notations, but adhering to the same binary format with the extension for assertions and DbC constructs, can represent their contracts in this common format that is understood by other components. This means behavioural contracts can accompany binary components, or more precisely they become part of the binary components. Programming languages can be extended in their own ways to support source level assertion specifications and stand a better chance of being accepted by programmers. At the same time, a common specification language with its own compiler is also possible. Further, existing binary components could also have contracts added to them, without the need for their source code.
Source (C#, Eiffel, VB,...) with assertions
Normal source
Separate assertion specifications
Modified compilers
Compilers
Assertion compilers
Binary components Existing code and metadata Assertions information
Figure 1. Scheme to support general assertions and Design by ContractTM Second, we propose a strategy for handling DbC constructs in which a runtime service is integrated in the execution engine, allowing correct treatment of contract evolution through sub-typing to be achieved. With sub-typing and dynamic dispatch, it is often not known until runtime which method should actually be invoked. In our proposal the runtime service can wait until the dispatch is resolved, trace the sub-typing hierarchy and construct the right constraints to be monitored, obeying the rules of covariance and contra-variance. Third, with such a runtime service, correct exception handling in case of constraint violation can be implemented. If a pre-condition of an operation is violated, it is the caller’s responsibility and an exception to the caller should be raised. If a post-condition of an operation is violated, it is the callee’s responsibility and an exception to the callee should be raised. With our runtime service, checks are performed outside the bodies of methods and therefore in case of violations, the right exceptions can be assigned to the right parties. Conversely, other code instrumentation techniques, where code for pre-condition checking is merged with the method body, cause pre-condition exception to occur in the callee. Even with a special exception type, it risks being accidentally caught by a catch-all written by the programmer. Likewise, if an operation’s post-conditions are checked after it has returned, i.e. in the caller, then the operation is not made accountable for its role in violating the post-conditions. In addition, because runtime monitoring is not ‘hard compiled’ into the code, flexible monitoring policies through configuration are possible. In component based systems, integration tests cannot be performed by the components’ producers. Therefore the producers may wish to have the preconditions monitored. Similarly, a client of these components might require their post-conditions to be checked initially. System integrators might want to change these policies based on their experience with the constituent components. Moreover, our scheme can help reduce the difficulty of handling object aliasing and re-entrance. In object-oriented programming, object aliasing and re-entrance are the norm but they create subtle problems due to potentially inconsistent state being observable to outsiders during method execution [25]. With proper DbC application, internal calls are allowed without class invariant checks while qualified calls must pass class invariant checks (in addition to pre-condition checks). This means if an object is in inconsistent state, calls from other objects are not possible. The object’s programmer need only deal with self re-entrance, and since all the code is under his/her control, it is easier to get it right, with care. Unlike code instrumentation, our scheme enables differentiated treatment of qualified and unqualified calls. It is also envisaged that with a common support mechanism for assertions in binary components, more expressive specification techniques may be developed and implemented to help deal with such issues
as object re-entrance, and non-functional aspects of specification. For example, support for state test functions [25] might be implemented.
3 Implementation We are currently implementing the scheme described above in the CLI environment, using the Microsoft Shared Source Implementation, Rotor [19]. We are currently extending the CLI portable executable format in a backward compatible way by adding extra metadata tables to hold assertions and DbC constructs. The new metadata tables hold Intermediate Language (IL) representations of the assertions, linking them with the right program elements, such as class for class invariants, methods for pre- and post-conditions. The linkage is designed in such a way that existing metadata tables are not modified at all. For each table that needs to be linked to, a new auxiliary table is created representing an extension column, containing the links. We are also implementing modifications to the class loaders, the JIT compiler, metadata APIs and a separate assertions support runtime service. The modifications to the class loaders and metadata APIs are to handle loading of the new metadata tables, to help construct equivalent runtime entities for the assertions and to enable reflection on the new constructs. The JIT compiler will be modified to enable interaction with the assertions support runtime service to handle runtime monitoring of class invariants, method pre- and post-conditions with appropriate exception handling. Further, we plan to modify the C# compiler to allow specification of assertions in C# programs. We envisage that the C# assertions notation would support native C# Boolean expressions, including state test functions to help deal with object re-entrance. We also hope to test our scheme with the Eiffel language by making the Eiffel compiler generate assertions and DbC constructs in our extension format.
4 Conclusion We maintain that a common support mechanism for general assertions and Design by Contract would enable better behavioural component contracts to be written and hence improve component quality. In this paper, we have proposed such a mechanism with support for general assertions and DbC in binary components in a language neutral way. We also described its advantages over existing techniques and its potential for enabling solutions to more subtle problems. Our implementation effort in the CLI environment is in progress. We plan to have an initial implementation of the ideas described in this paper available by the end of this year (2002).
5 Acknowledgements We thank our colleague Bertrand Meyer for many useful discussions on the ideas presented here. This project is partly supported by a Monash Graduate Scholarship for Nam Tran, and by a grant from Microsoft Research.
6 References 1. F. Bachmann, L. Bass, C. Buhman, S. Comella-Dorda, F. Long, J. Robert, R. Seacord, and K. Wallnau. Technical Concepts of Component-Based Software Engineering. Technical Report CMU/SEI-2000-TR-008, Software Engineering Institute, Carnegie Mellon University, 2000. 2. D. Bartetzko, C. Fischer, M. Moller and H. Wehrheim. Jass - Java with assertions. In Workshop on Runtime Verification, 2001, held in conjunction with the 13th Conference on Computer Aided Verification, CAV'01. 3. A. Beugnard, J.-M. Jezequel, N. Plouzeau, and D. Watkins. Making Components Contract Aware. Computer, July 1999. 4. C. D. T. Cicalese and S. Rotenstreich. Behavioral specification of distributed software component interfaces. Computer, July 1999. 5. A. Duncan and U. Hölzle. Adding Contracts to Java with Handshake. Technical Report TRCS9832, University of California, Santa Barbara, 1998.
6. ECMA, Standard ECMA-335: The Common Language Infrastructure, December 2001. 7. P. Freemantle, S. Weerawarana, R. Khalaf. Enterprise Services. Communications of the ACM, 45(10):77-82, 2002. 8. GNU Nana Project. Available at http://www.gnu.org/manual/nana/. 9. M. Karaorman, U. Hölzle, and J. Bruno. jContractor: Reflective Java Library to Support Designby-Contract. Technical Report TRCS98-31, University of California, Santa Barbara, 1998. 10. R. Kramer: iContract -- The Java Design by Contract Tool, Proceedings 26th TOOLS 1998, S.295307, Santa Barbara California. 11. G. T. Leavens, A. L. Baker, and C. Ruby. JML: A notation for detailed design. In H. Kilov, B. Rumpe, and I. Simmonds, editors, Behavioral Specifications of Businesses and Systems, pages 175-188. Kluwer Academic Publishers, Boston, 1999. 12. G. T. Leavens, K. R. M. Leino, E. Poll, C. Ruby and B. Jacobs. JML: notations and tools supporting detailed design in Java. In OOPSLA 2000 Companion, pages 105-106, 2000. 13. B. Meyer. Contracts for Components. Software Development, July 2000. 14. B. Meyer. Object Oriented Software Construction. 2nd Edition, 1997. Prentice Hall PTR Upper Saddle River. 15. B. Meyer. Polyglot Programming. Software Development, May 2002. 16. B. Meyer. Rules for Component Builders. Software Development, May 1999. 17. B. Meyer and C. Mingins. Component-Based Development: From Buzz to Spark. Computer, July 1999. 18. B. Meyer, C. Mingins, and H. Schmidt. Providing trusted component to the software industry. Computer, May 1998. 19. Microsoft Corporation. The Microsoft Shared Source CLI Implementation. Available at http://msdn.microsoft.com/net/sscli/. 20. Object Management Group. OMG Unified Modeling Language Specification, Version 1.4, 2001. 21. R. H. Reussner. The use of parameterised contracts for architecting systems with software components. In Jan Bosch, and Clemens Szyperski, editors, Proceedings of the Sixth International Workshop on Component-Oriented Programming (WCOP'01), June 2001. 22. M. Stal. Web services: beyond component-based computing. Communications of the ACM, 45(10):71-76, 2002. 23. Sun Microsystems Inc. Java Core Reflection. Available at http://java.sun.com/j2se/1.3/docs/guide/reflection/spec/java-reflectionTOC.doc.html 24. C. Szyperski. Components and Contracts. Software Development, May 2000. 25. C. Szyperski. Component Software: Beyond Object-Oriented Programming. ACM Press and Addison-Wesley, Reading, MA, 1998.