Code generation for Event-B

6 downloads 112107 Views 3MB Size Report
with other code generators for Event-B. The EventB2Java. Java code generator ...... ation can generate Ada code in addition to Java, we were interested in ...
Code generation for Event-B

Víctor Rivera, Néstor Cataño, Tim Wahls & Camilo Rueda

International Journal on Software Tools for Technology Transfer ISSN 1433-2779 Int J Softw Tools Technol Transfer DOI 10.1007/s10009-015-0381-2

1 23

Your article is protected by copyright and all rights are held exclusively by SpringerVerlag Berlin Heidelberg. This e-offprint is for personal use only and shall not be selfarchived in electronic repositories. If you wish to self-archive your article, please use the accepted manuscript version for posting on your own website. You may further deposit the accepted manuscript version in any repository, provided it is only made publicly available 12 months after official publication or later and provided acknowledgement is given to the original source of publication and a link is inserted to the published article on Springer's website. The link must be accompanied by the following text: "The final publication is available at link.springer.com”.

1 23

Author's personal copy Int J Softw Tools Technol Transfer DOI 10.1007/s10009-015-0381-2

REGULAR PAPER

Code generation for Event-B Víctor Rivera1 · Néstor Cataño2 · Tim Wahls3 · Camilo Rueda2

© Springer-Verlag Berlin Heidelberg 2015

Abstract Event-B is a modelling language and a formal methods approach for correct construction of software. This paper presents our work on code generation for Event-B, including the definition of a syntactic translation from EventB to JML-annotated Java programs, the implementation of the translation as the EventB2Java tool, and two case studies on the use of EventB2Java. The first case study is on implementing an Android application with the aid of the EventB2Java tool, and the second on testing an Event-B specification of the Tokeneer security-critical system. Additionally, we have benchmarked our EventB2Java tool against two other Java code generators for Event-B. Keywords Android · Code generation · Event-B · Formal methods · Java · JML · EventB2Java · Rodin · Tokeneer

B

Néstor Cataño [email protected] Víctor Rivera [email protected] Tim Wahls [email protected] Camilo Rueda [email protected]

1

The Software Engineering Lab, The Innopolis University, Kazan, Russia

2

Department of Computer Science, Pontificia Universidad Javeriana, Cali, Colombia

3

Department of Mathematics and Computer Science, Dickinson College, Carlisle, USA

1 Introduction The development of safety-critical reactive systems is intrinsically difficult. Event-B is a formal modelling language for reactive systems and a formal software development methodology in which software systems are initially conceived in a very abstract way and then refined [4] into code. This paper reports on our work on code generation for Event-B [2]. The main contributions of this work are (i) the definition of a full-fledged translation from Event-B to JML-annotated [33] Java programs, (ii) the implementation of this translation as the EventB2Java tool, and (iii) two case studies and extensive benchmarking results comparing our tool (EventB2Java) with other code generators for Event-B. The EventB2Java Java code generator largely supports Event-B’s syntax. A first key feature of our translation is that it can be applied to both abstract and refinement Event-B models. Hence, EventB2Java tool users can generate code for a very abstract and incomplete Event-B model of a system, check user’s intention in Java—whether the system behaves as expected, and then continue developing the Event-B model to correct any issues and add additional functionality as needed. EventB2Java can produce sequential or multi-threaded Java implementations of Event-B models. A second key feature of the proposed translation is the generation of (JML) formal specifications along with the Java code. This feature enables users to write custom code that replaces the code generated by EventB2Java, and then use existing JML tools [13] to verify that the custom code is correct. To validate our work on code generation for Event-B, we present two case studies: the first on the development of an Android application with EventB2Java, and the second on testing an Event-B model of the Tokeneer safety-critical system. More concretely, the first case study demonstrates

123

Author's personal copy V. Rivera et al.

how EventB2Java can be used as part of a software development methodology to generate the core functionality (the Model) of an Android application that is organised following the MVC (Model–View–Controller) software pattern [28], whilst the second case study demonstrates how EventB2Java and Java Unit (JUnit) testing [35] can be used to refine (improve) an Event-B model to conform to an existing System Test Specification (STS) document. To compare our work with the existing state of the art, we benchmarked EventB2Java against two competing tools for nine Event-B models and six comparison criteria.1 Our work has partially been published elsewhere. A preliminary version of the translation to Java and JML is presented in [44]. The rest of the work presented here is unpublished, including the two case studies and the EventB2Java tool benchmark. In the following, Sect. 2 introduces Event-B and JML, Sect. 3 presents the translation from Event-B to JMLannotated Java programs, and Sect. 4 presents the implementation of the EventB2Java tool. Section 5 presents a case study on software development with EventB2Java and Sect. 6 a case study on the use of EventB2Java in testing a securitycritical access control system modelled in Event-B. Section 7 presents our tool benchmark. Finally, Sect. 8 presents related work, and Sect. 9 concludes and mentions future work.

2 Background In this section we give a broad view of the Event-B formal method, and a brief introduction to JML. The expression formal method refers to a direct technique for constructing dependable systems. The system is dependable when there is evidence that its benefits outweigh its risks. A direct technique is one that focuses dependability on the system satisfying some critical properties, rather than on the functions or tasks it should perform. A formal method provides ways to integrate these properties into the system design and to mathematically prove system compliance with them. 2.1 The Event-B method Event-B is a formal modelling language for reactive systems, introduced by Abrial [2], which allows the modelling of complete systems (software plus hardware devices). Event-B is based on Action Systems [6], a formalism describing the behaviour of a system by the (atomic) actions that the system carries out. An Action System describes the state space of a system and the possible actions that can be executed in it. Thus, the purpose of Event-B is to describe a single frame1

The EventB2Java tool and the results of the benchmark are available at http://poporo.uma.pt/EventB2Java.

123

work as composed of a system and the way that it reacts to its environment. Event-B models are composed of contexts and machines. Contexts define constants, uninterpreted sets and their properties expressed as axioms, while machines define variables and their properties, and state transitions expressed as events. The initialisation event computes the initial state of a machine. An event is composed of a guard and an action. The guard (written between keywords where and then) represents conditions that must hold in a state for the event to trigger. The action (written between keywords then and end) computes new values for state variables, thus performing an observable state transition. If the system reaches a state where no event guard holds, it halts and is said to have deadlocked. There is no requirement that the system should halt, and indeed, most Event-B models represent systems that run forever. If halting is desired, the system can be modelled using convergent events that monotonically decrease the value of a natural number expression called the machine variant. Such events can only be triggered in states where the value of the variant is non-negative. Additionally, the system may reach a state where the guards of more than one event hold. In this situation, the system is said to be non-deterministic: Event-B semantics allows any of the events whose guards are satisfied to be triggered. In Event-B, systems are typically modelled via a sequence of refinements. First, an abstract machine is developed and verified to satisfy whatever correctness and safety properties are desired. Refinement machines are used to add more detail to the abstract machine until the model is sufficiently concrete for hand or automated translation to code. Refinement proof obligations are discharged to ensure that each refinement is a faithful model of the previous machine, so that all machines satisfy the correctness properties of the original. Figure 1 presents a simplified version of an Event-B model for social networking (taken and adapted from [18]). The initialisation event starting on line 14 gives initial values to the state (machine) variables. Two further events are shown: one that is triggered when any user uploads a new content item (the upload event on line 22), and the other triggered when a content item is to be hidden from some user page (the hide event on line 34). The upload event uploads a content item c1 to the account of person p1. c1 is a fresh item content so that c1 ∈ contents. The hide event hides content item c1 from the pages of person p1. The construct: any x where G(s, c, v, x) then v := A(s, c, v, x) end specifies a non-deterministic event that can be triggered in a state where the guard G(s, c, v, x) holds for some bounded value x, sets s, constants c, and machine variables v. When the event is triggered, a value for x satisfying G(s, c, v, x) is non-deterministically chosen and the event action v :=

Author's personal copy Code generation for Event-B

2.2 JML

Fig. 1 A simplified social networking machine in the Event-B language

A(s, c, v, x) is executed with x bound to that value. The correctness condition of the event requires that, for any x chosen, the new values of the state variables computed by the action of the event maintain the invariant properties of the machine. The semantics of events thus models a system that is controlled by interactions from the environment (i.e. user actions) that may occur at any time. The example in Fig. 1 uses the Rodin [3] tool notation, where predicates on different lines are implicitly conjoined and actions on different lines are executed simultaneously. The “\” symbol is used for set difference.

JML [33] is an interface specification language for Java. It is designed for specifying the behaviour of Java classes, and is included directly in Java source files using special comment markers //@ and /*@ */. JML’s type system includes all built-in Java types and additional types representing mathematical sets, sequences, functions and relations, which are represented as JML specified Java classes in the org.jmlspecs.models package. Similarly, JML expressions are a superset of Java expressions, with the addition of notations such as ==> for logical implication, \exists for existential quantification, and \forall for universal quantification. JML class specifications can include invariant clauses (assertions that must be satisfied in every visible state of the class), initially clauses (specifying conditions that the post-state of every class constructor must satisfy), and history constraints (specified with the keyword constraint, that are similar to invariants, with the additional ability to relate pre- and post-states of a method). Concrete JML specifications can be written directly over fields of the Java class. JML provides pre-post style specifications for Java methods describing software contracts [38]. JML uses keywords requires for method pre-conditions, ensures for normal method post-conditions, and assignable and modifies for frame conditions (lists of locations whose values may change from the pre-state to the poststate of a method). The pre-state is the state on method entry and the post-state is the state on method exit. A normal_behavior method specification states that if the method pre-condition holds in the pre-state of the method, then it will always terminate in a normal state, and the postcondition will hold in this state. In a JML ensures clause, the keyword \old is used to indicate expressions that must be evaluated in the pre-state of the method—all other expressions are evaluated in the post-state. The \old keyword can also be used in history constraints, providing a convenient way to specify (for example) that the post-state value of a field is always equal to the pre-state value, thus making the field a constant. Figure 2 presents a partial translation of the Event-B machine in Fig. 1 to JML. The details of the translation algorithm are presented in Sect. 3—our purpose here is primarily to give an example of a JML specification. Carrier sets CONTENTS and PERSONS are translated as static and final fields of type BSet, along with history constraints that specify that they are immutable (lines 4–11). Variables persons and contents are fields of type BSet, and pages and owner are BRelations (lines 12–17). These classes represent sets and relations, and are closely related to the JMLEqualsSet and JMLEqualsToEqualsRelation classes in the org.jmlspecs.models package. The

123

Author's personal copy V. Rivera et al.

Fig. 2 Part of the JML translation of the Event-B model in Fig. 1

methods of these classes implement Event-B set and relation operations, so the invariant (lines 19–24) is equivalent to the Event-B invariant on lines 9–12 of Fig. 1. Declaring the fields spec_public allows them to be used in public specifications. The guard_hide method is the translation of the guard of the hide event. Declaring a method as pure (line 33) has the same effect as assignable \nothing. The specification of the run_hide method uses two specification cases connected by the keyword also (line 41). The first case specifies that the pair (c1, p1) is removed from pages if the guard_hide method returns true. The second specifies that no state changes are allowed if guard_hide returns false. Only pure methods can be invoked within a JML specification.

3 The translation from Event-B to JML-annotated Java programs We present our translation from Event-B to Java and JML using three operators (EB2Prog, EB2Java and EB2Jml), which we define via syntactic rewriting rules. The primary operator is EB2Prog, which translates Event-B to JMLannotated Java programs. It uses EB2Java to obtain the Java

123

Fig. 3 The translation of machine M, and the context C that M sees

part of the translation and EB2Jml to obtain the JML part. For example, Event-B invariants are translated only as JML specifications, and so the definition of EB2Jml has a rule for invariants, while EB2Java does not. On the other hand, the translation of constants includes a Java part and a JML part, so the EB2Prog rule for constants refers to both of the EB2Java and EB2Jml rules for constants. The translation further employs operators Mod that returns the set of variables that a Java method can assign to, Pred that translates an Event-B predicate or expression, TypeOf that returns the type of a variable or constant, FreeVar that returns the set of variables that occur free in an expression, and Stat1 and Stat2 that are used in translating Event-B machine variants. An Event-B machine is translated as a Java class. In translating a machine, EB2Prog not only considers the information provided by the machine, but also the contexts the machine sees. Figure 3 presents Rule M that translates a

Author's personal copy Code generation for Event-B

machine M that sees context ct x. The translation includes two parts: the translation E of the events and the translation of the machine itself. The machine is translated as a Java class that includes JML class and method specifications. Each event is translated to a separate Java class. The translation of each event includes an object reference to the machine class. The translation of the machine includes the translation of the context the machine sees. Hence, the Java translation of the machine includes the translation of carrier sets, constants and axioms declared within the machine context. It also includes the translation of variables and invariants declared within the machine. The initialisation event is translated to JML as a post-condition B1 of the constructor of the machine class, and as Java code B2 that initialises a machine object. Refinement machines are translated in the same way as abstract machines since Rodin properly adds abstract machine components to the internal representation of the refining machine. Refining and extending events (defined using refines and extends, respectively) are translated in the same manner as abstract events for the same reasons. We translate carrier sets and constants as class attributes, and restrict those attributes for verification purposes. Hence, carrier sets are translated as class attributes with the addition of a history constraint that prevents any change in their values. As we have no type information about carrier sets, they are simply translated as sets of integers. EB2Jml(sets s) = SM EB2Java(sets s) = SA EB2Prog(sets s) = SM SA EB2Jml(sets s) = //@ public static constraint s.equals(\old(s));

(Set)

(Set)

EB2Java(sets s) = public static final BSet s = new Enumerated( Integer.MIN_VALUE,Integer.MAX_VALUE);

EB2Jml(constants c) = CM EB2Java(constants c) = CA EB2Prog(constants c) = CM CA

EB2Jml(constants c) = //@ public static constraint c.equals(\old(c));

(Cons)

TypeOf(c) = Type val = AxiomTheoremValue() EB2Java(constants c) = public static final Type c = val;

(Set)

Pred(X (s, c)) = X EB2Jml(axioms X (s, c)) = //@ public static invariant X;

(Axiom)

Machine variables are translated to class attributes. The JML keyword spec_public makes a protected or private attribute or method public to any JML specification.

EB2Prog(variables v) = /*@ spec_public */ private Type v;

(Var)

In Event-B, every event must maintain the machine invariants. In JML, invariants state properties that must hold in every visible system state, specifically after the execution of the class constructor and after a method terminates. This is semantically equivalent to conjoining the invariant to the post-condition of each method and the constructor. Since the initialisation event translates to the post-condition of the class constructor (see below), and the actions of each other event translate as the post-condition of an “atomic” run_evt method (in Fig. 4), Event-B invariants are naturally translated as JML invariants. Pred(I (s, c, v)) = I

Function AxiomTheoremValue has not yet been implemented in EventB2Java.

(Cons)

As axioms are mainly used to specify properties of constants and carrier sets, they are translated as static invariants. A JML static invariant can only refer to static fields, and so this approach is consistent with our translation of constants and carrier sets as static fields. Translating axioms to static invariants makes it clearer that they should not refer to machine variables, for example.

TypeOf(v) = Type

Translation of constants follows a similar pattern to the translation of carrier sets, except that in Event-B, the values of constants are constrained by axioms. The helper operator TypeOf translates the type of an Event-B variable or constant to the Java representation of that type. Function AxiomTheoremValue returns a value of type Type that satisfies the axioms defined in the contexts the machine sees.2

2

(Cons)

EB2Jml(invariants I (s, c, v)) = //@ public invariant I;

(Inv)

123

Author's personal copy V. Rivera et al.

EB2Jml(A(s, c, v)) = A EB2Jml(event initialisation then A(s, c, v) end) = A EB2Java(A(s, c, v)) = A EB2Java(event initialisation then A(s, c, v) end) = A

(Init)

(Init)

Other (non-initialisation) Event-B events can be either ordinary, convergent or anticipated. Convergent events are used for modelling terminating systems. Anticipated events denote some abstract behaviour that is to be made precise in a future refinement. Convergent events must monotonically decrease the machine variant (a given natural number expression), and anticipated events cannot increase the machine variant. Events that are convergent or anticipated are only enabled if the value of the variant is non-negative. An Event-B variant expression “variant E(s, c, v)” is translated by EB2Prog as a method that returns the result of evaluating the translation of E.

Pred(E(s, c, v)) = E EB2Prog(variant E(s, c, v)) = /*@ public normal_behavior requires true; assignable \nothing; ensures \result == E;*/ public /*@ pure */ int variant() {return E;}

Fig. 4 The translation of a standard event

Machines include a specialised initialisation event that gives initial values to state variables. This event is translated by EB2Jml as the post-condition of the (only) constructor for the Java class resulting from the translation of the machine, and by EB2Java as the body of that constructor. Both translations give initial values to the translation of the machine variables.

123

(Variant)

Rules Status1 and Status2 below are used (by Rule Any in Fig. 4) to impose the conditions associated with variants on the guards and actions of convergent and anticipated events. Translating variant expressions in this manner allows the user to verify that a customised method implementation is consistent with the meaning of the translated event—for example, since the translation of a convergent event refers to the translation of the variant in the post-condition of its JML specification, the user can employ JML machinery to verify that the customised implementation does in fact decrease the variant. The return type of method variant() above is int. This and the use of rule Status1 in Rule Any ensure that the variant is a natural number expression as required by Event-B.

Stat1(status ordinary) = true

(Status1)

Stat1(status convergent) = m.variant() >= 0

(Status1)

Author's personal copy Code generation for Event-B

Stat1(status anticipated) = m.variant() >= 0 Stat2(status ordinary) = true

(Status1)

(Status2)

Stat2(status convergent) = m.variant() < \old(m.variant())

(Status2)

Stat2(status anticipated) = m.variant()

Suggest Documents