PCC Reading List

This is a reading list on proof-carrying-code (PCC), composed for a course on Formal Methods in Software Development, in the summer term 2007. The latest version of the slides for both classes of the PCC sub-course are available here

In order to get an overview of proof-carrying-code in general, check out George Necula's PCC page and Peter Lee's Overview of PCC. Both have good summaries about the essence of PCC and give further links. As tutorials on PCC check out the articles by Necula and Hofmann at the Marktoberdorf Summer School in 2003 and 2005, respectively. The most influential paper in the field is probably Necula's POPL97 paper, which started the research in this direction and is therefore a must-read (see also the earlier tech report). The basis for the main example in the first class of the PCC subcourse was the POPL paper on CCured (a longer version is available as journal article). Other papers that were only shortly covered in the course are Appel's paper on foundational PCC and Besson et al's paper on Certified Abstract Interpretation. Several on-line demos are available, and they are listed below together with the papers: Touchstone, CCured, MRG.

Finally, here some links to overview pages, and to some projects in the PCC area:


[1] Martin Abadi and Rustan Leino. A logic of object-oriented programs. In Michel Bidoit and Max Dauchet, editors, TAPSOFT '97: Theory and Practice of Software Development, 7th International Joint Conference CAAP/FASE, Lille, France, volume 1214, pages 682-696. Springer-Verlag, New York, N.Y., 1997. superceeded by [2].
[ bib ]

We develop a logic for reasoning about object-oriented programs. The logic is for a language with an imperative semantics and aliasing, and accounts for self-reference in objects. It is much like a type system for objects with subtyping, but our specifications go further than types in detailing pre- and postconditions. We intend the logic as an analogue of Hoare logic for objectoriented programs. Our main technical result is a soundness theorem that relates the logic to a standard operational semantics.
[2] Martin Abadi and Rustan Leino. A Logic of Object-Oriented Programs. In Verification: Theory and Practice, pages 11-41. Springer-Verlag, 2004.
[ bib | .pdf ]

We develop a logic for reasoning about object-oriented programs. The logic is for a language with an imperative semantics and aliasing, and accounts for self-reference in objects. It is much like a type system for objects with subtyping, but our specifications go further than types in detailing pre-and postconditions. We intend the logic as an analogue of Hoare logic for object-oriented programs. Our main technical result is a soundness theorem that relates the logic to a standard operational semantics.
[3] Andrew W. Appel. Foundational Proof-Carrying Code. In LICS'01 - Symposium on Logic in Computer Science, June 2001.
[ bib | .pdf ]

Proof-carrying code is a framework for the mechani- cal verification of safety properties of machine language programs, but the problem arises of quis custodiat ip- sos custodes2014who will verify the verifier itself? Founda- tional proof-carrying code is verification from the small- est possible set of axioms, using the simplest possible ver- ifier and the smallest possible runtime system. I will de- scribe many of the mathematical and engineering prob- lems to be solved in the construction of a foundational proof-carrying code system.
[4] Andrew W. Appel and Amy P. Felty. Dependent Types Ensure Partial Correctness of Theorem Provers. Journal of Functional Programming, 14(1):3-19, 2004.
[ bib | .pdf ]

Static type systems in programming languages allow many errors to be detected at compile time that wouldn't be detected until runtime otherwise. Dependent types are more expressive than the type systems in most programming languages, so languages that have them should allow programmers to detect more errors earlier. In this paper, using the Twelf system, we show that dependent types in the logic programming setting can be used to ensure partial correctness of programs which implement theorem provers, and thus avoid runtime errors in proof search and proof construction. We present two examples: a tactic-style interactive theorem prover and a union-find decision procedure.
[5] D. Aspinall, L. Beringer, M. Hofmann, H-W. Loidl, and A. Momigliano. A Program Logic for Resources. Theoretical Computer Science, 2006. Special Issue on Global Computing. To appear.
[ bib | .pdf ]

We introduce a reasoning infrastructure for proving statements on resource consumption in an abstract fragment of the Java Virtual Machine Language (JVML). The infrastructure is based on a small hierarchy of program logics, with increasing levels of abstraction: at the top there is a type system for a high-level language that encodes resource consumption. The infrastructure is designed to be used in a proof-carrying code (PCC) scenario, where mobile programs can be equipped with formal evidence that they have good resource behaviour. This article presents the core logic in our infrastructure, a VDM-style program logic for partial correctness, that can make statements about resource consumption in a general form. We establish some important results for this logic, including soundness and completeness with respect to a resource-aware operational semantics for the JVML. We also present a second logic built on top of the core logic, which is used to express termination; it is also shown to be sound and complete. The entire infrastructure has been formalised in the theorem prover Isabelle/HOL, both to enhance confidence in the meta-theoretical results, and to provide a prototype implementation for PCC. We give examples to show the usefulness of this approach, including proofs of resource bounds on code resulting from compiling high-level functional programs.
[6] D. Aspinall, S. Gilmore, M. Hofmann, D. Sannella, and I. Stark. Mobile Resource Guarantees for Smart Devices. In CASSIS'04 - Intl. Workshop on Construction and Analysis of Safe, Secure and Interoperable Smart Devices, volume 3362 of LNCS, pages 1-26, Marseille, France, March 10-13, 2004. Springer-Verlag.
[ bib | .pdf ]

We present the Mobile Resource Guarantees framework: a system for ensuring that downloaded programs are free from run-time violations of resource bounds. Certificates are attached to code in the form of efficiently checkable proofs of resource bounds; in contrast to cryptographic certificates of code origin, these are independent of trust networks. A novel programming language with resource constraints encoded in function types is used to streamline the generation of proofs of resource usage.
[7] D. Aspinall and K. MacKenzie. Mobile Resource Guarantees and Policies. In Construction and Analysis of Safe, Secure, and Interoperable Smart Devices (CASSIS'05), LNCS 3956, pages 16-36, Nice, March 8-11, 2005. Springer.
[ bib | .pdf ]

This paper introduces notions of resource policy for mobile code to be run on smart devices, to integrate with the proof-carrying code architecture of the Mobile Resource Guarantees (MRG) project. Two forms of policy are used: guaranteed policies which come with proofs and target policies which describe limits of the device. A guaranteed policy is expressed as a function of a methods input sizes, which determines a bound on consumption of some resource. A target policy is defined by a constant bound and input constraints for a method. A recipient of mobile code chooses whether to run methods by comparing between a guaranteed policy and the target policy. Since delivered code may use methods implemented on the target machine, guaranteed policies may also be provided by the platform; they appear symbolically as assumptions in delivered proofs. Guaranteed policies entail proof obligations that must be established from the proof certificate. Before proof, a policy checker ensures that the guaranteed policy refines the target policy; our policy format ensures that this step is tractable and does not require proof. Delivering policies thus mediates between arbitrary target requirements and the desirability to package code and certificate only once.
[8] David Aspinall, Lennart Beringer, Martin Hofmann, Hans-Wolfgang Loidl, and Alberto Momigliano. A program logic for resource verification. In Proceedings of 17th International Conference on Theorem Proving in Higher Order Logics (TPHOLs2004), volume 3223 of Lecture Notes in Computer Science, pages 34-49, Heidelberg, September 2004. Springer-Verlag.
[ bib | .pdf ]

We present a program logic for reasoning about resource consumption of programs written in Grail, an abstract fragment of the Java Virtual Machine Language. Serving as the target logic of a certifying compiler, the logic exploits Grail's dual nature of combining a functional interpretation with object-oriented features and a cost model for the JVM. We present the resource-aware operational semantics of Grail, the program logic, and prove soundness and completeness. All of the work described has been formalised in the theorem prover Isabelle/HOL, which provides us with an implementation of the logic as well as confidence in the results. We conclude with examples of using the logic for proving resource bounds on code resulting from compiling high-level functional programs.
[9] David Aspinall and Adriana Compagnoni. Heap Bounded Assembly Language. Journal of Automated Reasoning, 31(3-4):261-302, September 2003. Special Issue on Proof-Carrying Code.
[ bib | .pdf ]

We present a first-order linearly typed assembly language, HBAL, that allows the safe reuse of heap space for elements of different types. Linear typing ensures the single pointer property, disallowing aliasing, but allowing safe in-place update compilation of programming languages. We prove that HBAL is sound for a low-level untyped model of the machine, using a satisfiability relation which captures when a location correctly models a value of some type. This interpretation is closer to the machine than previous abstract machines used for typed assembly language models, and we separate typing of the store from an untyped operational semantics of programs, as would be required for proof-carrying code. Our ultimate aim is to design a family of assembly languages which have high-level typing features which are used to express resource bound constraints. We want to link up the assembly level with high-level languages expressing similar constraints, to provide end-to-end guarantees, and a viable framework for proof-carrying code. HBAL is a first exemplifying step in this direction. It is designed as a target low-level language for Hofmann's LFPL (Hofmann, 2000b) language. Programs written in LFPL run in a bounded amount of heap space, and this property carries over when they are compiled to HBAL: the resulting program does not allocate store or assume an external garbage collector. Following LFPL, we include a special diamond resource type which stands for a unit of heap space of uncommitted type, similar in spirit to Tofte-Talpin's notion of region.
[10] Gilles Barthe, Mariela Pavlova, and Gerardo Schneider. Precise analysis of memory consumption using program logics. In Third IEEE International Conference on Software Engineering and Formal Methods (SEFM 2005), pages 86-95, 7-9 September, Koblenz, Germany, 2005. IEEE Computer Society.
[ bib | .pdf ]

Memory consumption policies provide a means to control resource usage on constrained devices, and play an important role in ensuring the overall quality of soft ware systems, and in particular resistance against re source exhaustion attacks. Such memory consumption policies have been previously enforced through static analysis, which yield automatic bounds at the cost of precision, or run-time analysis, which incur an overhead that is not acceptable for constrained devices.

In this paper, we study the use of logical methods to specify and statically verify precise memory consumption policies for Java bytecode programs. First, we demonstrate how the Bytecode Specification Language (a variant of the Java Modelling Language tailored to bytecode) can be used to specify precise memory consumption policies for (sequential) Java applets, and how verification tools can be used to enforce such memory consumption policies.Second,we consider the issue of inferring some of the annotations required to express the memory consumption policy,and report on an inference algorithm.

Our broad conclusion is that logical methods provide a suitable means to specify and verify expressive memory consumption policies, with an acceptable overhead.

[11] Stefan Berghofer and Tobias Nipkow. Proof Terms for Simply Typed Higher Order Logic. In TPHOL'02 - Theorem Proving in Higher Order Logics, volume 1869, pages 38-52. Springer, 2000.
[ bib | .ps.gz ]

This paper presents proof terms for simply typed, intuitionistic higher order logic, a popular logical framework. Unification-based algorithms for the compression and reconstruction of proof terms are described and have been implemented in the theorem prover Isabelle. Experimental results confirm the effectiveness of the compression scheme.
[12] L. Beringer, M. Hofmann, A. Momigliano, and O. Shkaravska. Automatic Certification of Heap Consumption. In Logic for Programming, Artificial Intelligence, and Reasoning (LPAR'04), LNCS 3452, pages 347-362, Montevideo, Uruguay, March 14-18, Feb 2005. Springer.
[ bib | .pdf ]

We present a program logic for verifying the heap consumption of low-level programs. The proof rules employ a uniform assertion format and have been derived from a general purpose program logic [8]. In a proof-carrying code scenario, the inference of invariants is delegated to the code provider, who employs a certifying compiler that generates a certificate from program annotations and analysis. The granularity of the proof rules matches that of the linear type system presented in [24], which enables us to perform verification by replaying typing derivations in a theorem prover, given the specifications of individual methods. The resulting verification conditions are of limited complexity, and are automatically discharged. We also outline a proof system that relaxes the linearity restrictions and relates to the type system of usage aspects presented in [?].
[13] F. Besson, T. Jensen, and D. Pichardie. Proof-Carrying Code from Certified Abstract Interpretation and Fixpoint Compression. Theoretical Computer Science. Special Issue on Applied Semantics, 2006. Also: Tech. Report INRIA-5751. To appear.
[ bib | pdf ]

Proof-Carrying Code (PCC) is a technique for downloading mobile code on a host machine while ensuring that the code adheres to the host's safety policy. We show how certified abstract interpretation can be used to build a PCC architecture where the code producer can produce program certificates automatically. Code consumers use proof checkers derived from certified analysers to check certificates. Proof checkers carry their own correctness proofs and accepting a new proof checker amounts to type checking the checker in Coq. Certificates take the form of strategies for reconstructing a fixpoint and are kept small due to a technique for fixpoint compression. The PCC architecture has been implemented and evaluated experimentally on a byte code language for which we have designed an interval analysis that allows to generate certificates ascertaining that no array-out-of-bounds accesses will occur.
[14] Ajay Chander, David Espinosa, Nayeem Islam, Peter Lee, and George Necula. Enforcing Resource Bounds via Static Verification of Dynamic Checks. In ESOP'05 - European Symposium on Programming, volume 3444 of LNCS, pages 311-, Edinburgh, UK, April 4-8, 2005.
[ bib ]

We classify existing approaches to resource-bounds checking as static or dynamic. Dynamic checking performs checks during program execution, while static checking performs them before execution. Dynamic checking is easy to implement but incurs runtime cost. Static checking avoids runtime overhead but typically involves difficult, often incomplete program analyses. In particular, static checking is hard in the presence of dynamic data and complex program structure. We propose a new resource management paradigm that offers the best of both worlds. We present language constructs that let the code producer optimize dynamic checks by placing them either before each resource use, or at the start of the program, or anywhere in between. We show how the code consumer can then statically verify that the optimized dynamic checks enforce his resource bounds policy. We present a practical language that is designed to admit decidable yet efficient verification and prove that our procedure is sound and optimal. We describe our experience verifying a Java implementation of tar for resource safety. Finally, we outline how our method can improve the checking of other dynamic properties.
[15] Bor-Yuh Evan Chang, A. Chlipala, G. Necula, and R. Schneck. The Open Verifier Framework for Foundational Verifiers. In Workshop on Types in Language Design and Implementation (TLDI'05). ACM, January 2005.
[ bib | .pdf ]

We present the Open Verifier approach for verifying untrusted code using customized verifiers. This approach can be viewed as an instance of foundational proof-carrying code where an untrusted program can be checked using the verifier most natural for it instead of using a single generic type system. In this paper we focus on a specialized architecture designed to reduce the burden of expressing both type-based and Hoare-style verifiers.

A new verifier is created by providing an untrusted executable extension module, which can incorporate directly pre-existing non-foundational verifiers based on dataflow analysis or type checking. The extensions control virtually all aspects of the verification by carrying on a dialogue with the Open Verifier using a language designed both to correspond closely to common verification actions and to carry simple adequacy proofs for those actions.

We describe the design of the trusted core of the Open Verifier, along with our experience implementing proof-carrying code, typed assembly language, and dataflow or abstract interpretation based verifiers in this unified setting.

[16] Bor-Yuh Evan Chang, Karl Crary, Margaret DeLap, Robert Harper, Jason Liszka, Tom Murphy VII, and Frank Pfenning. Trustless Grid Computing in ConCert. In GRID 2002: Third International Workshop on Grid Computing, volume 2536 of LNCS, Baltimore, MD, November 2002.
[ bib | .pdf ]

We believe that fundamental to the establishment of a grid computing framework where all (not just large organizations) are able to effectively tap into the resources available on the global network is the establishment of trust between grid application developers and resource donors. Resource donors must be able to trust that their security, safety, and privacy policies will be respected by programs that use their systems.

In this paper, we present a novel solution based on the notion of certified code that upholds safety, security, and privacy policies by examining intrinsic properties of code. Certified code complements authentication and provides a foundation for a safe, secure, and efficient framework that executes native code. We describe the implementation of such a framework known as the ConCert software.

[17] Christopher Colby, Peter Lee, and George C. Necula. A Proof-Carrying Code architecture for Java. In CAV'00 - International Conference on Computer Aided Verification. ACM Press, Chicago, IL, July 2000.
[ bib | .ps ]

In earlier work, Necula and Lee developed proof-carrying code(PCC) [3, 5], which is a mechanism for ensuring the safe behavior of programs. In PCC, a program contains both the code and an encoding of an easy-to-check proof. The validity of the proof, which can be automatically determined by a simple proof-checking program, implies that the code, when executed, will behave safely according to a user-supplied formal definition of safe behavior. Later, Necula and Lee demonstrated the concept of a certifying compiler[6, 7]. Certifying compilers promise to make PCC more practical by compiling high-level source programs into optimized PCC binaries completely automatically, as opposed to depending on semi-automatic theorem-proving techniques. Taken together, PCC and certifying compilers provide a possible solution to the code safety problem, even in applications involving mobile code [4].

In this paper we describe a PCC architecture comprising two tools:

(1) A thin PCC layer implemented in C that protects a host system from unsafe software. The host system can be anything from a desktop computer down to a smartcard. The administrator of the host system specifies a safety policy in a variant of the Edinburgh Logical Framework (LF) [1]. This layer loads PCC binaries, which are Intel x86 ob ject files that contain a section providing a binary encoding of a safety proof, and checks them against the safety policy before installing the software.

(2) A software-development tool that produces x86 PCC binaries from Java classfiles. It is implemented in Objective Caml [2]. From a developer's perspective, this tool works just like any other compiler, with an interface similar to javac or gcc. Behind the scenes, the tool produces x86 machine code along with a proof of type safety according to the Java typing rules.

[18] K. Crary and S. Weirich. Resource Bound Certification. In POPL'00 - Symposium on Principles of Programming Languages, pages 184-198,, Boston, MA, January 2000.
[ bib | .ps.gz ]

Various code certification systems allow the certification and static verification of important safety properties such as memory and control-flow safety. These systems are valuable tools for verifying that untrusted and potentially malicious code is safe before execution. However, one important safety property that is not usually included is that programs adhere to specific bounds on resource consumption, such as running time. We present a decidable type system capable of specifying and certifying bounds on resource consumption. Our system makes two advances over previous resource bound certification systems, both of which are necessary for a practical system: We allow the execution time of programs and their subroutines to vary, depending on their arguments, and we provide a fully automatic compiler generating certified executables from source-level programs. The principal device in our approach is a strategy for simulating dependent types using sum and inductive kinds.
[19] David L. Detlefs, K. Rustan M. Leino, Greg Nelson, and James B. Saxe. Extended Static Checking. SRC Research Report 159, Compaq Systems Research Center, December 1998.
[ bib | .ps ]

The paper describes a mechanical checker for software that catches many common programming errors, in particular array index bounds errors, nil dereference errors, and synchronization errors in multi-threaded programs. The checking is performed at compile-time. The checker uses an automatic theorem-prover to reason about the semantics of conditional statements, loops, procedure and method calls, and exceptions. The checker has been implemented for Modula-3. It has been applied to thousands of lines of code, including mature systems code as well as fresh untested code, and it has found a number of errors.
[20] V. Dornic, P. Jouvelot, and D.K. Gifford. Polymorphic Time Systems for Estimating Program Complexity. ACM Letters on Programming Languages and Systems, 1(1):33-45, March 1992.
[ bib | .pdf ]

We present a new approach to static program analysis that permits each expression in a program to be assigned an execution time estimate. Our approach uses atime system in conjunction with a conventional type system to compute both the type and the time of an expression. The time of an expression is either an integer upper bound on the number of ticks the expression will execute, or the distinguished element long that indicates that the expression contains a loop and thus may run for an arbitrary length of time. Every function type includes a latent time that is used to communicate its expected execution time from the point of its definition to the points of its use. Unlike previous approaches a time system works in the presence of first-class functions and separate compilation. In addition, time polymorphism allows the time of a function to depend on the times of any functions that it takes as arguments. Time estimates are useful when compiling programs for multiprocessors in order to balance the overhead of initiating a concurrent computation against the expected execution time of the computation. The correctness of our time system is proven with respect to a dynamic semantics.
[21] Vincent Dornic, Pierre Jouvelot, and David K. Gifford. Polymorphic time systems for estimating program complexity. ACM Letters on Programming Languages and Systems (LOPLAS), 1(1):33-45, 1992.
[ bib ]

We present a new approach to static program analysis that permits each expression in a program to be assigned an execution time estimate. Our approach uses a time system in conjunction with a conventional type system to compute both the type and the time of an expression. The time of an expression is either an integer upper bound on the number of ticks the expression will execute, or the distinguished element long that indicates that the expression contains a loop, and thus may run for an arbitrary length of time. Every function type includes a latent time that is used to communicate its expected execution time from the point of its definition to the points of its use. Unlike previous approaches, a time system works in the presence of first-class functions and separate compilation. In addition, time polymorphism allows the time of a function to depend on the times of any functions that it takes as arguments. Time estimates are useful when compiling programs for multiprocessors in order to balance the overhead of initiating a concurrent computation against the expected execution time of the computation. The correctness of our time system is proven with respect to a dynamic semantics.
[22] B. Grobauer. Cost Recurrences for DML Programs. In ICFP'01, Florence, Italy, September 2001. ACM Press.
[ bib | .ps.gz ]

A cost recurrence describes an upper bound for the running time of a program in terms of the size of its input. Finding cost recurrences is a frequent intermediate step in complexity analysis, and this step requires an abstraction from data to data size. In this article, we use information contained in dependent types to achieve such an abstraction: Dependent ML (DML), a conservative extension of ML, provides dependent types that can be used to associate data with size information, thus describing a possible abstraction. We automatically extract cost recurrences from first-order DML programs, guiding the abstraction from data to data size with information contained in DML type derivations.
[23] M. Hofmann. Semantik und Verifikation. Lecture Notes, 1998. TU Darmstadt.
[ bib ]
[24] M. Hofmann and S. Jost. Static Prediction of Heap Space Usage for First-Order Functional Programs. In POPL'03 - Symposium on Principles of Programming Languages, volume 38, pages 185-197, New Orleans, LA, USA, January 2003. ACM Press.
[ bib | .ps ]

We show how to efficiently obtain linear a priori bounds on the heap space consumption of first-order functional programs. The analysis takes space reuse by explicit deallocation into account and also furnishes an upper bound on the heap usage in the presence of garbage collection. It covers a wide variety of examples including, for instance, the familiar sorting algorithms for lists, including quicksort. The analysis relies on a type system with resource annotations. Linear programming (LP) is used to automatically infer derivations in this enriched type system. We also show that integral solutions to the linear programs derived correspond to programs that can be evaluated without any operating system support for memory management. The particular integer linear programs arising in this way are shown to be feasibly solvable under mild assumptions.
[25] M. Hofmann, H-W. Loidl, and L. Beringer. Certification of Quantitative Properties of Programs. In Logical Aspects of Secure Computer Systems, Marktoberdorf, Aug 2-13, 2005. IOS Press. Lecture Notes of the Marktoberdorf Summer School 2005. To appear.
[ bib | .pdf ]

In the context of mobile and global computing knowledge of quantitative properties of programs is particularly important. Here are some typical scenarios: (1) A provider of distributed computational power may only be willing to offer this service upon receiving dependable guarantees about the required resource consumption. (2) A user of a handheld device, wearable computer, or smart card might want to know that a downloaded application will definitely run within the limited amount of memory available. (3) Third-party software updates for mobile phones, household appliances, or car electronics should come with a guarantee not to set system parameters beyond manufacturer-specified safe limits.

Requiring certificates of specified resource consumption will also help to prevent mobile agents from performing denial of service attacks using bona fide host environments as a portal. These lecture notes describe how such quantitative resource-related properties can be inferred automatically using type systems and how the results of such analysis can be turned into unforgeable certificates using a proof-carrying code framework.

[26] Martin Hofmann. A type system for bounded space and functional in-place update. Nordic Journal of Computing, 7(4):258-289, 2000.
[ bib | .ps.gz ]

We show how linear typing can be used to obtain functional programs which modify heap-allocated data structures in place.

We present this both as a ``design pattern'' for writing C-code in a functional style and as a compilation process from linearly typed first-order functional programs into malloc-free Ccode.

The main technical result is the correctness of this compilation.

The crucial innov ation over previous linear typing schemes consists of the introduction of a resource type D which controls the number of constructor symbols such as consin recursive definitions and ensures linear space while restricting expressive power surprisingly little.

While the space efficiency brought about by the new typing scheme and the compilation into C can also be realised by with state-of-the-art optimising compilers for functional languages such as Ocaml[16], the present method provides guaranteed bounds on heap space which will be of use for applications such as languages for embedded systems or automatic certification of resource bounds.

We show that the functions expressible in the system are precisely those computable on a linearly space-bounded T uring machine with an unbounded stack. By a result of Cook this equals the complexity class 'exponential time'. A tail recursive fragment of the language captures the complexity class 'linear space'.

We discuss various extensions, in particular an extension with FIFO queues admitting constant time catenation and enqueuing, and an extension of the type system to fully-fledged intuitionistic linear logic.

[27] R.J.M. Hughes and L. Pareto. Recursion and Dynamic Data Structures in Bounded Space: towards Embedded ML Programming. In ICFP'99 - International Conference on Functional Programming, pages 70-81, Paris, France, September 1999. ACM Press.
[ bib | .ps ]

We present a functional language with a type system such that well typed programs run within stated space-bounds. The language is a strict, first-order variant of ML with constructs for explicit storage management. The type system is a variant of Tofte and Talpin's region inference system to which the notion of sized types, of Hughes, Pareto and Sabry, has been added.
[28] R.J.M. Hughes, L. Pareto, and A. Sabry. Proving the Correctness of Reactive Systems Using Sized Types. In POPL'96 - Symposium on Principles of Programming Languages, St. Petersburg Beach, Florida, January 1996. ACM.
[ bib | .ps ]

We have designed and implemented a type-based analysis for proving some basic properties of reactive systems. The analysis manipulates rich type expressions that contain information about the sizes of recursively defined data-structures. Sized types are useful for detecting deadlocks, non-termination, and other errors in embedded programs. To establish the soundness of the analysis we have developed an appropriate semantic model of sized types.

Keywords: sized types, reactive systems, embedded software, liveness and termination analysis, productivity
[29] M. Huisman and B. Jacobs. Java Program Verfication via a Hoare Logic with Abrupt Termination. In T. Maibaum, editor, FASE'00 - Fundamental Approaches to Software Engineering, volume 1783 of LNCS, pages 284-303. Springer-Verlag, 2000.
[ bib | .ps.Z ]

This paper formalises a semantics for statements and expressions (in sequential imperative languages) which includes non-termination, normal termination and abrupt termination (e.g. because of an exception, break, return or continue). This extends the traditional semantics underlying e.g. Hoare logic, which only distinguishes termination and non-termination. An extension of Hoare logic is elaborated that includes means for reasoning about abrupt termination (and side-effects). It prominently involves rules for reasoning about while loops, which may contain exceptions, breaks, continues and returns. This extension applies in particular to Java. As an example, a standard pattern search algorithm in Java (involving a while loop with returns) is proven correct using the proof-tool PVS.
[30] Gerwin Klein and Tobias Nipkow. A machine-checked model for a Java-like language, virtual machine and compiler. Technical Report 0400001T.1, National ICT Australia, Sydney, March 2004.
[ bib | .pdf ]

We introduce Jinja, a Java-like programming language with a formal semantics designed to exhibit core features of the Java language architecture. Jinja is a compromise between realism of the language and tractability and clarity of the formal semantics. The following aspects are formalised: a big and a small step operational semantics for Jinja and a proof of their equivalence; a type system and a definite initialization analysis; a type safety proof of the small step semantics; a virtual machine (JVM), its operational semantics and its type system; a type safety proof for the JVM; a bytecode verifier, i.e. dataflow analyzer for the JVM; a correctness proof of the bytecode verifiers w.r.t. the type system; a compiler and a proof that it preseves semantics and well-typedness.

The emphasis of this work is not on particular language features but on providing a unified model of the source language, the virtual machine and the compiler. The whole development has been carried out in the theorem prover Isabelle/HOL.

[31] Thomas Kleymann. Hoare Logic and VDM: Machine-Checked Soundness and Completeness Proofs. PhD thesis, LFCS, 1999.
[ bib | .pdf ]

Investigating soundness and completeness of verification calculi for imperative programming languages is a challenging task. Many incorrect results have been published in the past. We take advantage of the computer-aided proof tool LEGO to interactively establish soundness and completeness of both Hoare Logic and the operation decomposition rules of the Vienna Development Method (VDM) with respect to operational semantics. We deal with parameterless recursive procedures and local variables in the context of total correctness. As a case study, we use LEGO to verify the correctness of Quicksort in Hoare Logic.

As our main contribution, we illuminate the rôle of auxiliary variables in Hoare Logic. They are required to relate the value of program variables in the final state with the value of program variables in the initial state. In our formalisation, we reflect their purpose by interpreting assertions as relations on states and a domain of auxiliary variables. Furthermore, we propose a new structural rule for adjusting auxiliary variables when strengthening preconditions and weakening postconditions. This rule is stronger than all previously suggested structural rules, including rules of adaptation.

With the new treatment, we are able to show that, contrary to common belief, Hoare Logic subsumes VDM in that every derivation in VDM can be naturally embedded in Hoare Logic. Moreover, we establish completeness results uniformly as corollaries of Most General Formula theorems which remove the need to reason about arbitrary assertions.

[32] Naoki Kobayashi and Atsushi Igarashi. Resource Usage Analysis. In POPL02 - Principles of Programming Languages, Portland, OR, January 2002.
[ bib | .pdf ]

It is an important criterion of program correctness that a program accesses resources in a valid manner. For example, a memory region that has been allocated should be eventually deallocated, and after the deallocation, the region should no longer be accessed. A file that has been opened should be eventually closed. So far, most of the methods to analyze this kind of property have been proposed in rather specific contexts (like studies of memory management and verification of usage of lock primitives), and it was not so clear what is the essence of those methods or how methods proposed for individual problems are related. To remedy this situation, we formalize a general problem of analyzing resource usage as a resource usage analysis problem, and propose a type-based method as a solution to the problem.
[33] K. Rustan M. Leino. Recursive object types in a logic of object-oriented programs. Nordic Journal of Computing, 5(4):330-360, 1998.
[ bib ]

This paper formalizes a small object-oriented programming notation. The notation features imperative commands where objects can be shared (aliased) and is rich enough to allow subtypes and recursive object types. The syntax, type checking rules, axiomatic semantics, and operational semantics of the notation are given. A soundness theorem showing the consistency between the axiomatic and operational semantics is also given. A simple corollary of the soundness theorem demonstrates the soundness of the type system. Because of the way types, fields, and methods are declared, no extra effort is required to handle recursive object types.
[34] K. Rustan M. Leino. Recursive object types in a logic of object-oriented programs. Technical Note 1997-025a, Digital Systems Research Center, Palo Alto, CA, January 1998. Superseded by [33], but with complete operational semantics and soundness proof.
[ bib | .ps.gz ]

This paper formalizes a small object-oriented programming notation. The notation features imperative commands where objects can be shared (aliased), and is rich enough to allow subtypes and recursive object types. The syntax, type checking rules, axiomatic semantics, and operational semantics of the notation are given. A soundness theorem, showing the consistency between the axiomatic and operational semantics is stated and proved. A simple corollary of the soundness theorem demonstrates the soundness of the type system. Because of the way types, fields, and methods are declared, no extra effort is required to handle recursive object types.
[35] K. Rustan M. Leino. Applications of extended static checking. In Patrick Cousot, editor, SAS'01 - International Static Analysis Symposium, volume 2126 of LNCS, pages 185-193, July 2001.
[ bib | .ps ]

Extended static checking is a powerful program analysis technique. It translates into a logical formula the hypothesis that a given program has some particular desirable properties. The logical formula, called a verification condition, is then checked with an automatic theorem prover. The extended static checking technique has been built into a couple of program checkers. This paper discusses other possible applications of the technique to the problem of producing quality software more quickly.
[36] X. Leroy. Bytecode verification for Java smart card. Software Practice and Experience, 32, 2002.
[ bib | .pdf ]

This article presents a novel approach to the problem of bytecode verification for Java Card applets. By relying on prior off­card bytecode transformations, we simplify the bytecode verifier and reduce its memory requirements to the point where it can be embedded on a smart card, thus increasing significantly the security of post­issuance downloading of applets on Java Cards. This article describes the on­card verification algorithm and the off­card code transformations, and evaluates experimentally their impact on applet code size.
[37] Farhad Mehta and Tobias Nipkow. Proving pointer programs in higher-order logic. Information and Computation, 199:200-227, 2005.
[ bib | .ps.gz ]

Building on the work of Burstall, this paper develops sound modelling and reasoning methods for imperative programs with pointers: heaps are modelled as mappings from addresses to values, and pointer structures are mapped to higher-level data types for verification. The programming language is embedded in higher-order logic. Its Hoare logic is derived. The whole development is purely definitional and thus sound. Apart from some smaller examples, the viability of this approach is demonstrated with a non-trivial case study. We show the correctness of the Schorr-Waite graph marking algorithm and present part of its readable proof in Isabelle/HOL.
[38] Aloysius K. Mok and Weijiang Yu. TINMAN: A Resource Bound Security Checking System for Mobile Code. In European Symposium on Research in Computer Security, volume 2502 of LNCS, Zurich, Switzerland, October 14-16, 2002. Springer-Verlag.
[ bib | .pdf ]

Resource security pertains to the prevention of unauthorized usage of system resources that may not directly cause corruption or leakage of information. common breach of resource security is the class of attacks called DoS (Denial of Service) attacks. This paper proposes an architecture called TINMAN whose goal is to efficiently and effectively safeguard resource security for mobile source code written in C. We couple resource usage checks at the programming language level and at the run-time system level. This is achieved by the generation of resource skeleton from source code. This resource skeleton abstracts the resource consumption behavior of the program which is validated by means of resource usage certificate that is derived from proof generation. TINMAN uses resource-usage checking tools to generate proof obligations required of the resource usage certificate and provides full coverage by monitoringany essential property not guaranteed by the certificates. We shall describe the architecture of TINMAN and give some experimental results of the preliminary TINMAN implementation.
[39] P. Müller and A. Poetzsch-Heffter. A Programming Logic for Sequential Java. In ESOP'99 - European Symposium on Programming, LNCS, pages 208-225. Springer, 1999.
[ bib | .ps.gz ]

A Hoare-style programming logic for the sequential kernel of Java is presented. It handles recursive methods, class and interface types, subtyping, inheritance, dynamic and static binding, aliasing via object references, and encapsulation. The logic is proved sound w.r.t. an SOS semantics by embedding both into higher-order logic.
[40] Tom Murphy VII, Karl Crary, Robert Harper, and Frank Pfenning. A Symmetric Modal Lambda Calculus for Distributed Computing. Technical Report CMU-CS-04-105, Carnegie Mellon University, 2004.
[ bib | .ps ]

We present a foundational language for distributed programming, called Lambda 5, that addresses both mobility of code and locality of resources. In order to construct our system, we appeal to the powerful propositions-as-types interpretation of logic. Specifically, we take the possible worlds of the intuitionistic modal logic IS5 to be nodes on a network, and the connectives Box and Diamond to reflect mobility and locality, respectively. We formulate a novel system of natural deduction for IS5, decomposing the introduction and elimination rules for Box and Diamond, thereby allowing the corresponding programs to be more direct. We then give an operational semantics to our calculus that is type-safe, logically faithful, and computationally realistic.
[41] G.C. Necula and P. Lee. Efficient Representation and Validation of Proofs. In LICS'98 - Symposium on Logic in Computer Science, Indianapolis, IN, 1998.
[ bib | .ps ]

This paper presents a logical framework derived from the Edinburgh Logical Framework (LF) that can be used to obtain compact representations of proofs and efficient proof checkers. These are essential ingredients of any application that manipulates proofs as first-class objects, such as a Proof-Carrying Code system, in which proofs are used to allow the easy validation of properties of safety-critical or untrusted code.

Our framework, which we call LFi, inherits from LF the capability to encode various logics in a natural way. In addition, the LFi framework allows proof representations without the high degree of redundancy that is characteristic of LF representations. The missing parts of LFi proof representations can be reconstructed during proof checking by an efficient reconstruction algorithm. We also describe an algorithm that can be used to strip the unnecessary parts of an LF representation of a proof. The experimental data that we gathered in the context of a Proof-Carrying Code system shows that the savings obtained from using LFi instead of LF can make the difference between practically useless proofs of several megabytes and manageable proofs of tens of kilobytes.

This paper is an abbreviated version of a longer (70 pages) technical report. Read it if you want to see the detailed (15 pages) proofs of soundness of the efficient proof-checking algorithm that is used in PCC.

[42] George Necula. Proof-carrying code. In POPL'97 - Symposium on Principles of Programming Languages, Paris, France, January 1997.
[ bib | .ps ]

This paper describes proof-carrying code (PCC) a mechanism by which a host system can determine with certainty that it is safe to execute a program supplied (possibly in binary form) by an untrusted source. For this to be possible, the untrusted code producer must supply with the code a safety proof that attests to the code's adherence to a previously defined safety policy . The host can then easily and quickly v alidate the proof without using cryptography and without consulting any external agents. In order to gain preliminary experience with PCC, we have performed several case studies. We show in this paper how proof-carrying code might be used to develop safe assembly-language extensions of ML programs. In the context of this case study , we present and prove the adequacy of concrete representations for the safety policy, the safety proofs, and the proof validation. Finally, we briefly discuss how we use proof-carrying code to develop network packet filters that are faster than similar filters developed using other techniques and are formally guaranteed to be safe with respect to a given operating system safety policy.
[43] George Necula. Compiling with Proofs. PhD thesis, Carnegie Mellon University, September 1998.
[ bib | .pdf ]

One of the major challenges of building software systems is to ensure that the various components fit together in a well-defined manner. This problem is exacerbated by the recent advent of software components whose origin is unknown or inherently untrusted, such as mobile code or user extensions for operating- system kernels or database servers. Such extensions are useful for implementing an efficient interaction model between a client and a server because several data exchanges between them can be saved at the cost of a single code exchange.

In this dissertation, I propose to tackle such system integrity and security problems with techniques from mathematical logic and programming-language semantics. I propose a framework, called proof-carrying code, in which the extension provider sends along with the extension code a representation of a formal proof that the code meets certain safety and correctness requirements. Then, the code receiver can ensure the safety of executing the extension by validating the attached proof. The major advantages of proof-carrying code are that it requires a simple trusted infrastructure and that it does not impose run-time penalties for the purpose of ensuring safety.

In addition to the concept of proof-carrying code, this dissertation contributes the idea of certifying compilation. A certifying compiler emits, in addition to optimized target code, function specifications and loop invariants that enable a theorem-proving agent to prove non-trivial properties of the target code, such as type safety. Such a certifying compiler, along with a proof-generating theorem prover, is not only a convenient producer of proof-carrying code but also a powerful software-engineering tool. The certifier also acts as an effective referee for the correctness of each compilation, thus simplifying considerably compiler testing and maintenance.

A complete system for proof-carrying code must also contain a proof-generating theorem prover for the purpose of producing the attached proofs of safety. This dissertation shows how standard decision procedures can be adapted so that they can produce detailed proofs of the proved predicates and also how these proofs can be encoded compactly and checked efficiently. Just like for the certifying compiler, a proof-generating theorem prover has significant software- engineering advantages over a traditional prover. In this case, a simple proof checker can ensure the soundness of each successful proving task and indirectly assist in testing and maintenance of the theorem prover.

[44] George C. Necula. Proof and System Reliability, chapter Proof-Carrying Code: Design and Implementation. Springer-Verlag, 2001.
[ bib | .pdf ]

Proof-Carrying Code (PCC) is a general mechanism for verifying that a code fragment can be executed safely on a host system. The key technical detail that makes PCC simple yet very powerful is that the code fragment is required to be accompanied by a detailed and precise explanation of why it satisfies the safety policy. This leaves the code receiver with the simple task of verifying that the explanation is correct and that it matches the code in question.

In this paper we explore the basic design and the implementation of a system using Proof-Carrying Code. We consider two possible representations for the proofs carried with the code, one using Logical Frameworks and the other using hints for guiding a non-deterministic proof reconstructor. In the second part of the paper we discuss issues related to generating the required proofs, which is done through cooperation between a compiler and a theorem prover. We will conclude with a presentation of experimental results in the context of verifying that the machine-code output of a Java compiler is type safe.

[45] George C. Necula, Jeremy Condit, Matthew Harren, Scott McPeak, and Westley Weimer. CCured: Type-Safe Retrofitting of Legacy Software. ACM Transactions on Programming Languages and Systems (TOPLAS), 2004.
[ bib | .pdf ]

This article describes CCured, a program transformation system that adds type safety guarantees to existing C programs. CCured attempts to verify statically that memory errors cannot occur, and it inserts run-time checks where static verification is insufficient.CCured extends C's type system by separating pointer types according to their usage, and it uses a surprisingly simple type inference algorithm that is able to infer the appropriate pointer kinds for existing C programs. CCured uses physical subtyping to recognize and verify a large number of type casts at compile time. Additional type casts are verified using run-time type information. CCured uses two instrumentation schemes, one that is optimized for performance and one in which metadata is stored in a separate data structure whose shape mirrors that of the original user data. This latter scheme allows instrumented programs to invoke external functions directly on the program's data without the use of a wrapper function.We have used CCured on real-world security-critical network daemons to produce instrumented versions without memory-safety vulnerabilities, and we have found several bugs in these programs. The instrumented code is efficient enough to be used in day-to-day operations.
[46] George C. Necula and Peter Lee. Proof-Carrying Code. Technical Report CMU-CS-96-165, School of Computer Science, Carnegie Mellon University Pittsburgh, PA, September 1996.
[ bib | .ps ]

This report describes Proof-Carrying Code, a software mechanism that allows a host system to determine with certainty that it is safe to execute a program supplied by an untrusted source. For this to be possible, the untrusted code supplier must provide with the code a safety proof that attests to the code's safety properties. The code consumer can easily and quickly validate the proof without using cryptography and without consulting any external agents. In order to gain preliminary experience with proof-carrying code, we have performed a series of case studies. In one case study, we write safe assembly-language network packet filters. These filters can be executed with no run-time overhead, beyond a one-time cost of 1 to 3 milliseconds for validating the attached proofs. The net result is that our packet filters are formally guaranteed to be safe and are faster than packet filters created using Berkeley Packet Filters, Software Fault Isolation, or safe languages such as Modula-3. In another case study we show how proof-carrying code can be used to develop safe assembly-language extensions of the a simplified version of the TIL run-time system for Standard ML.
[47] George C. Necula and Peter Lee. Safe, Untrusted Agents Using Proof-Carrying Code. In Special Issue on Mobile Agent Security, volume 1419 of LNCS. Springer-Verlag, 1998.
[ bib | .ps ]

This paper is intended to be both a comprehensive implementation guide for a Proof-Carrying Code system and a case study for using PCC in a mobile agent environment. Specifically, the paper describes the use of PCC for enforcing memory safety, access control and resource usage bounds for untrusted agents that access a database.
[48] George C. Necula and Peter Lee. Proof Generation in the Touchstone Theorem Prover. In CADE'00 - International Conference on Automated Deduction, Pittsburgh, PA, June 2000.
[ bib | .ps ]
[49] George C. Necula, Scott McPeak, and Westley Weimer. CCured: Type-Safe Retrofitting of Legacy Code. In POPL02 - Symposium on Principles of Programming Languages, London, U.K., January 2002. ACM Press.
[ bib | .pdf ]

In this paper we propose a scheme that combines type inference and run-time checking to make existing C programs type safe. We describe the CCured type system, which extends that of C by separating pointer types according to their usage. This type system allows both pointers whose usage can be verified statically to be type safe, and pointers whose safety must be checked at run time. We prove a type soundness result and then we present a surprisingly simple type inference algorithm that is able to infer the appropriate pointer kinds for existing C programs.

Our experience with the CCured system shows that the inference is very effective for many C programs, as it is able to infer that most or all of the pointers are statically verifiable to be type safe. The remaining pointers are instrumented with efficient run-time checks to ensure that they are used safely. The resulting performance loss due to run-time checks is 0-150% , which is several times better than comparable approaches that use only dynamic checking. Using CCured we have discovered programming bugs in established C programs such as several SPECINT95 benchmarks.

[50] George C. Necula and Robert R. Schneck. A Sound Framework for Untrustred Verification-Condition Generators. In LICS03 - Symposium on Logic in Computer Science, July 2002.
[ bib | .pdf ]

We propose a framework called configurable proof- carrying code, which allows the untrusted producer of mobile code to provide the bulk of the code verifier used by a code receiver to check the safety of the received code. The resulting system is both more flexible and also more trustworthy than a standard proof-carrying code system, because only a small part of the verifier needs to be trusted, while the remaining part can be configured freely to suit the safety policy on one hand, and the structure of the mobile code on the other hand.

In this paper we describe formally the protocol that the untrusted verifier must follow in the interaction with the trusted infrastructure. We present a proof of the soundness of the system, and we give preliminary evidence that the architecture is expressive enough to delegate to the untrusted verifier even the handling of loop invariants, indirect jumps and calling conventions.

[51] George C. Necula and Robert R. Schneck. A Sound Framework for Untrustred Verification-Condition Generators. In LICS03 - IEEE Symposium on Logic in Computer Science, July 2003.
[ bib ]
[52] Tobias Nipkow. Hoare logics for recursive procedures and unbounded nondeterminism. In J. Bradfield, editor, Computer Science Logic (CSL 2002), volume 2471 of LNCS, pages 103-119. Springer, 2002.
[ bib | .pdf ]

This paper presents sound and complete Hoare logics for partial and total correctness of recursive parameterless procedures in the context of unbounded nondeterminism. For total correctness, the literature so far has either restricted recursive procedures to be deterministic or has studied unbounded nondeterminism only in conjunction with loops rather than procedures. We consider both single procedures and systems of mutually recursive procedures. All proofs are performed with the help of the theorem prover Isabelle/HOL.
[53] Tobias Nipkow. Jinja: Towards a comprehensive formal semantics for a Java-like language. In H. Schwichtenberg and K. Spies, editors, Proc. Marktobderdorf Summer School 2003. IOS Press, 2003. To appear.
[ bib | .pdf ]

Jinja is a Java-like programming language with a formal semantics designed to exhibit core features of Java. It is a compromise between realism of the language and tractability and clarity of the formal semantics. A big and a small step operational semantics are defined and shown equivalent. A type system and a definite initialization analysis are defined and type safety of the small step semantics is shown. The whole development has been carried out in the theorem prover Isabelle/HOL.
[54] Peter O'Hearn, John Reynolds, and Hongseok Yang. Local Reasoning about Programs that Alter Data Structures. In CSL'01 - Annual Conference of the European Association for Computer Science Logic, LNCS, pages 1-19, Paris, 2001. Springer-Verlag.
[ bib | .pdf ]

We describe an extension of Hoare's logic for reasoning about programs that alter data structures. We consider a low-level storage model based on a heap with associated lookup, update, allocation and deallocation operations, and unrestricted address arithmetic. The assertion language is based on a possible worlds model of the logic of bunched implications, and includes spatial conjunction and implication connectives alongside those of classical logic. Heap operations are axiomatized using what we call the ``small axioms'', each of which mentions only those cells accessed by a particular command. Through these and a number of examples we show that the formalism supports local reasoning: A specification and proof can concentrate on only those cells in memory that a program accesses. This paper builds on earlier work by Burstall, Reynolds, Ishtiaq and O'Hearn on reasoning about data structures.
[55] David von Oheimb and Tobias Nipkow. Hoare logic for NanoJava: Auxiliary variables, side effects and virtual methods revisited. In Lars-Henrik Eriksson and Peter Alexander Lindsay, editors, Formal Methods - Getting IT Right (FME'02), volume 2391 of LNCS, pages 89-105. Springer, 2002.
[ bib | .ps.gz ]

We define NanoJava, a kernel of Java tailored to the investigation of Hoare logics. We then introduce a Hoare logic for this language featuring an elegant new approach for expressing auxiliary variables: by universal quantification on the outer logical level. Furthermore, we give simple means of handling side-effecting expressions and dynamic binding within method calls. The logic is proved sound and (relatively) complete using Isabelle/HOL.
[56] Frank Pfenning. Logical Frameworks, chapter Chapter 16, pages 977-1061. Elsevier Science and MIT Press, 2001.
[ bib | .pdf ]
[57] B. Reistad and D.K. Gifford. Static Dependent Costs for Estimating Execution Time. In LFP'94 - Conference on Lisp and Functional Programming, pages 65-78, Orlando, Florida, June 27-29, June 1994. ACM Press.
[ bib | .ps ]

We present the first system for estimating and using data-dependent expression execution times in a language with first-class procedures and imperative constructs. The presence of first-class procedures and imperative constructs makes cost estimation a global problem that can benefit from type information. We estimate expression costs with the aid of an algebraic type reconstruction system that assigns every procedure a type that includes a static dependent cost. A static dependent cost describes the execution time of a procedure in terms of its inputs. In particular, a procedure's static dependent cost can depend on the size of input data structures and the cost of input first-class procedures. Our cost system produces symbolic cost expressions that contain free variables describing the size and cost of the procedure's inputs. At run-time, a cost estimate is dynamically computed from the statically determined cost expression and run-time cost and size information. We present experimental results that validate our cost system on three compilers and architectures. We experimentally demonstrate the utility of cost estimates in making dynamic parallelization decisions. In our experience, dynamic parallelization meets or exceeds the parallel performance of any fixed number of processors.
[58] J. Reynolds. Separation Logic: A Logic for Shared Mutable Data Structures. In LICS'02 - Symposium on Logic in Computer Science, Copenhagen, Denmark, July 22-25, 2002.
[ bib | .ps.gz ]

In joint work with Peter O'Hearn and others, based on early ideas of Burstall, we have developed an extension of Hoare logic that permits reasoning about low-level imperative programs that use shared mutable data structure.

The simple imperative programming language is extended with commands (not expressions) for accessing and modifying shared structures, and for explicit allocation and deallocation of storage. Assertions are extended by introducing a ``separating conjunction'' that asserts that its subformulas hold for disjoint parts of the heap, and a closely related ``separating implication''. Coupled with the inductive definition of predicates on abstract data structures, this extension permits the concise and flexible description of structures with controlled sharing.

In this paper, we will survey the current development of this program logic, including extensions that permit unrestricted address arithmetic, dynamically allocated arrays, and recursive procedures. We will also discuss promising future directions.

[59] J. C. Reynolds. Syntactic control of interference. In POPL'78 - Symp. on Princ. of Prog. Lang., 1978.
[ bib | .ps.gz ]
[60] Donald Sannella, Martin Hofmann, David Aspinall, Stephen Gilmore, Ian Stark, Lennart Beringer, Hans-Wolfgang Loidl, Kenneth MacKenzie, Alberto Momigliano, and Olha Shkaravska. Mobile Resource Guarantees. In TFP05 - Trends in Functional Programing, volume 6, Tallinn, Estonia, Sep 23-24, 2005. Intellect.
[ bib | .pdf ]

The Mobile Resource Guarantees (MRG) project has developed a proof-carrying-code infrastructure for resources to be applied to mobile code. Key components of this infrastructure are a certifying compiler for a high-level language, a hierarchy of program logics, tailored for reasoning about resource consumption, and an embedding of the logics into a theorem prover. In this paper, we give an overview of the project's results, discuss the lessons learnt from it and introduce follow-up work in new projects that will build on these results.
[61] L. Unnikrishnan, S.D. Stoller, and Y.A. Liu. Automatic Accurate Stack Space and Heap Space Analysis for High-Level Languages. Technical Report 538, Computer Science Dept, Indiana University, April 2000.
[ bib | .ps.gz ]

This paper describes a general approach for automatic and accurate space and space-bound analyses for high-level languages, considering stack space, heap allocation and live heap space usage of programs. The approach is based on program analysis and transformations and is fully automatic. The analyses produce accurate upper bounds in the presence of partially known input structures. The analyses have been implemented, and experimental results confirm the accuracy.
[62] David von Oheimb. Hoare logic for Java in Isabelle/HOL. Concurrency and Computation: Practice and Experience, 13(13):1173-1214, 2001.
[ bib | .ps.gz ]

This article presents a Hoare-style calculus for a substantial subset of Java Card, which we call Java_light. In particular, the language includes side-effecting expressions, mutual recursion, dynamic method binding, full exception handling, and static class initialization. The Hoare logic of partial correctness is proved not only sound (w.r.t. our operational semantics of Java_light, described in detail elsewhere) but even complete. It is the first logic for an object-oriented language that is provably complete. The completeness proof uses a refinement of the Most General Formula approach. The proof of soundness gives new insights into the role of type safety. Further by-products of this work are a new general methodology for handling side-effecting expressions and their results, the discovery of the strongest possible rule of consequence, and a flexible Call rule for mutual recursion. We also give a small but non-trivial application example. All definitions and proofs have been done formally with the interactive theorem prover Isabelle/HOL. This guarantees not only rigorous definitions, but also gives maximal confidence in the results obtained.
[63] Martin Wildmoser and Tobias Nipkow. Certifying machine code safety: Shallow versus deep embedding. In K. Slind, A. Bunker, and G. Gopalakrishnan, editors, Theorem Proving in Higher Order Logics (TPHOLs 2004), volume 3223 of LNCS, pages 305-320. Springer, 2004.
[ bib | .pdf ]

We formalise a simple assembly language with procedures and a safety policy for arithmetic overflow in Isabelle/HOL. To verify individual programs we use a safety logic. Such a logic can be realised in Isabelle/HOL either as shallow or deep embedding. In a shallow embedding logical formulas are written as HOL predicates, whereas a deep embedding models formulas as a datatype. This paper presents and discusses both variants pointing out their specific strengths and weaknesses.
[64] Martin Wildmoser and Tobias Nipkow. Asserting Bytecode Safety. In ESOP'05 - European Symposium on Programming, volume 3444 of LNCS, pages 326-341, Edinburgh, UK, April 4-8, 2005.
[ bib | .pdf ]

We instantiate an Isabelle/HOL framework for proof carrying code to Jinja bytecode, a downsized variant of Java bytecode featuring objects, inheritance, method calls and exceptions. Bytecode annotated in a first order expression language can be certified not to produce arithmetic overflows. For this purpose we use a generic verification condition generator, which we have proven correct and relatively complete.
[65] Martin Wildmoser, Tobias Nipkow, Gerwin Klein, and Sebastian Nanz. Prototyping proof carrying code. In J.-J. Levy, E. Mayer, and J. Mitchell, editors, Exploring New Frontiers of Theoretical Informatics, pages 333-347. Kluwer, 2004.
[ bib | .pdf ]

We introduce a generic framework for proof carrying code, developed and mechanically verified in Isabelle/HOL. The framework defines and proves sound a verification condition generator with minimal assumptions on the underlying programming language, safety policy, and safety logic. We demonstrate its usability for prototyping proof carrying code systems by instantiating it to a simple assembly language with procedures and a safety policy for arithmetic overflow.
[66] Concert web page, June 2005.
[ bib | .html ]
[67] Touchstone web page, June 2005.
[ bib | .html ]
[68] Ccured online demo, June 2006.
[ bib | .html ]
[69] Mrg online demo, June 2006.
[ bib | http ]
[70] Touchstone online demo, June 2005.
[ bib | .html ]
[71] Hongwei Xi. Dependent Types for Program Termination Verification. Higher-order and Symbolic Computation, 15(1):91-131, March 2002.
[ bib | .pdf ]

Program termination verification is a challenging research subject of significant practical importance. While there is already a rich body of literature on this subject, it is still undeniably a difficult task to design a termination checker for a realistic programming language that supports general recursion. In this paper, we present an approach to program termination verification that makes use of a form of dependent types developed in Dependent ML (DML), demonstrating a novel application of such dependent types to establishing a liveness property. We design a type system that enables the programmer to supply metrics for verifying program termination and prove that every well-typed program in this type system is terminating. We also provide realistic examples, which are all verified in a prototype implementation, to support the effectiveness of our approach to program termination verification as well as its unobtrusiveness to programming. The main contribution of the paper lies in the design of an approach to program termination verification that smoothly combines types with metrics, yielding a type system capable of guaranteeing program termination that supports a general form of recursion (including mutual recursion), higher-order functions, algebraic datatypes, and polymorphism.

This file has been generated by bibtex2html 1.54
Hans-Wolfgang Loidl
Last modified: Mon Jun 25 20:43:54 2007 Stardate: [-29]7798.90