A Termination Analyser for Java Bytecode Based on Path-Length

Domains for the Static Analysis of Java. Our abstract domain for path-length (Section 6) abstracts a property of the heap, namely, the maximal length of a chain of pointers reachable from each variable in the program. From this point of view, it is related to a traditional normused to prove termination of logic programs, which measures the height of a term, seen as a tree. The main difference is that, for its definition, we need precise information about the shape of the heap at run-time at each program point. Namely, we need information about sharing and cyclicity of data structures. Determining an over-approximation of the pairs of program variables that share at each program point is an extensively studied problem. There is a huge literature about poin er or aliasing analysis [Choi et al. 1993; Steensgaard 1996] and about shapeanalysis [Wilhelm et al. 2002; Distefano et al. 2006] of data structures. Many flavours of such analyses are fully qualified for computing possible sharing pairs of variables. More generally, separation logic [Reynolds 2000; Ishtiaq and O’Hearn 2001] is a framework which allows one to define analyses of properties of the heap and can express properties like sharing and cyclicity of data structures. It is known, however, that a static analysis for sharing can be much more abstract than aliasing or shape analysis, which justifies the development of abstract domains which track those properties explicitly, rather than as a side-effect [Pollet et al. 2001]. Namely, the abstract domain, defined and proved correct in [Secci and Spoto 2005], is just made of sets of pairs of possibly sharing variables. This results in a static analysis which can be implemented in a completely context and flow sensitive way and still requires one or two orders of magnitude less time than, for instance, aliasing analysis [Payet and Spoto 2007]. It must be clear, however, that sharing is too abstract if possible aliasing is what is needed, but this is not the case in this paper. Tools for the Static Analysis of Java. Many tools have been devoted to the analysis or verification of Java or Java bytecode programs. Although such systems have not been used for termination analysis, we think that they could be instantiated for that purpose. They should be enriched with analyses computing information about the shape of the memory, such as our sharing and cyclicity analyses; hence some measure similar to our path-length information could be computed and termination proved by showing that, along loops and recursion, this measure is decreasing over a well-founded order. B ANDERA [Corbett et al. 2000] takes a source Java program and extracts compact finite-state models of the program which can then be sourced to a model checker. It also performs some static analyses. It includes a program slicer for better efficiency and uses abstract interpretation for the finite representation of the states. J AVA PATHFINDER [Visser et al. 2003] uses model-checking to explore the states of a Java program and its scheduling sequences. As a consequence, it has shown to be effective to prove properties of real-time Java [Lindstrom et al. 2005]. JMOPED[Suwimonteerabuth et al. 2007] is a test environment for a subset of Java. It uses model-checking to explore the set of states reachable from some input states taken from a testing set. It signals bugs or problems such as assertion violations, null pointer excep58 · F. Spoto and F. Mesnard and É. Payet tions and array bound violations. Testing is not in general complete, so it is hard to foresee an application of this tool to termination analysis, where termination must be proved for all input states. Moreover, only a subset of Java is considered, with strong limitations such as a ban of negative numbers. JMOPED has also been used for testing Java bytecode [Suwimonteerabuth et al. 2005], with strong limitations such as a bound on the heap size which prevents a new bytecode from occurring inside a loop. KEY [Ahrendt et al. 2005] is a tool for the design, implementation, specification and verification of object-oriented programs. It verifies properties expressed in the Object Constraint Language or in JML. It is a semi-automatic tool, based on theorem proving. Programs must first be annotated with the properties to prove and a theorem prover then attempts their proof with possible human interaction. BOOGIE [Barnett et al. 2005] is a program verifier for Spec# programs in the . NET framework. It has been recently applied to Java bytecode [Lehner and Müller 2007], by translating it into BOOGIEPL, the input language of BOOGIE. It includes a framework for abstract interpretation to build loop invariants that it uses to instrument he code. Invariants about the heap can be constructed through the abstract domain defined in [Chang and Leino 2005]. Namely, this allows one to track which parts of the heap are preserved across updates and get information about purity of function arguments. Proofs are built through theorem-proving. The goal of this tool is the proof of object invariants [Leino and Wallenburg 2008], that is, data consistency properties about the objects of a program. Those invariants might be violated within a small scope but must hold after that each call from the external environment has completed. Object invariants are specified by the user and verified by the system. The use of ownership [Leino and Müller 2004; Müller 2007] allows one to model invariants which must hold of data structures as a whole rather than for single component objects. It is also possible to prove class invariants, which are related to static fields [Leino and Müller 2005]. A distinguishing feature of these works is the modularity of the verification, which we currently lack. These works based on theorem proving cannot be considered fully automatic since the user has to provide a specification of the property to prove and the theorem prover will likely require human intervention to reach the proof. Moreover, although it is possible, in principle, to prove termination with such techniques, we are not aware of any general technique for that purpose. In object-oriented programs the set of classes to analyse must be extracted from the starting class, containing the main method, by using some form of application extraction. This extraction is important in order to avoid the analysis of all classes, even those that are not relevant for the analysis. Our JULIA tool uses a sophisticated algorithm based on [Palsberg and Schwartzbach 1991], rephrased for the Java bytecode. We are not aware of other tools implementing similar, very precise application extraction techniques. Previous Publications of this Material. The material presented in this paper is partially based on our previous work. [Secci and Spoto 2005] and [Rossignoli and Spoto 2006] present he sharing and cyclicity analyses that we use in Section 4. The path-length abstract domain has been defined in [Spoto et al. 2006]. The last three papers are presented for Java, while we rephrase their analyses here for Java bytecode and embed them into the semantic framework of [Payet and Spoto 2007], where the operational and denotational semantics of Section 5 are presented and their equivalence is shown. A Termination Analyser for Java Bytecode Based on Path-Length · 59