170 likes | 301 Vues
This paper discusses the reasoning about the correctness of object-oriented (OO) programs, emphasizing well-behaved invariants and data abstractions. It introduces Abstract Predicate Families (APF) to articulate relationships among data abstractions, enabling a higher level of reasoning. By employing two new specification mechanisms—export and axiom clauses—this approach improves modularity and soundness while allowing for flexibility in inheritance scenarios. The proposed methods are illustrated with examples from the Gobo data structure library, demonstrating their practical application in proving program correctness.
E N D
Chair of Software Engineering Reasoning about Multiple Related Abstractions with MultiStar Stephan van Staden, Cristiano Calcagno
Introduction Broad topic: reasoning about the correctness of OO programs In particular: well-behaved invariants Data abstractions pervade OO programs: • Language constructs: classes • Concepts: account, counter, person, stack
Abstract Predicate Families (APF) Purpose: data abstraction E.g. d + 100 < b x.deposits = d ˄x.balance = b APF predicate x.A(deps: d, bal: b) • Logical abstractions of data • APF predicate arguments are the only visible properties of the abstraction • Think in terms of interface and implementation. This enforces high-level reasoning • APF predicates can have different implementations in different classes • Inheritance-aware
Related abstractions Abstractions are often related:x.A(deps: d, bal: b) x.C(cnt: d) * x.R(bal: b) Possible implementations: One class Client Inheritance Counter c: int Counter c: int Balance b: int Account d: int b: int Account d: Counter b: Balance Balance b: int Account
The opportunity Correctness of code often depends on such relationships, but the original proof system allows only to pass APF predicates around Assume library routine use_counter(x) {x.C(cnt: d)}_{x.C(cnt: d+20)} Client reasoning: {x.A(deps: d, bal: b)} {x.C(cnt: d) * x.R(bal: b)} use_counter(x) {x.C(cnt: d+20) * x.R(bal: b)} // Code that assumes x.A(deps: d+20, bal: b) Client infers an A-based specification for use_counter Access control & call protocols: x.A(deps: d, bal: b) x.C(cnt: d) * x.R(bal: b) x.A(deps: d, bal: b) x.C(cnt: d) * x.R(bal: b)
The problem Original APF system lacks ways to • Specify relationships among abstractions • Verify them • Reason about code that relies on them Solutions must be flexible, since a property may apply to • Instances of particular classes • A whole class hierarchy Further requirements: soundness, modularity, simplicity
Our approach We use two new specification mechanisms • Export clauses for properties of individual classes • Axiom clauses for properties of entire class hierarchies Export clauses • Class C contains export P • Verification checks whether P follows from the APF assumptions of C • Clients can assume P • The paper contains examples
Our approach Axiom clauses • Class C contains axiom l: P • C and all its subclasses must implement axiom l • Subclasses can refine (i.e. strengthen) an axiom • Clients can assume ∀x <: C P[x/Current] • Dynamic type information is not necessary to use this axiom information E.g. axiom a1: A(deps: d, bal: b) C(cnt: d) * R(bal: b) Method body verification can use export and axiom information of all classes
More examples Impose representation constraints on subclasses • axiom C(cnt: c) CAccount(cnt: c) • All subclasses are forced to implement the C abstraction in the same way as class Account Diamond inheritance & view shifting • In class StudentMusician:axiom S(age: a, exm: e) * R1(pfm: p) M(age: a, pfm: p) * R2(exm: e) • Ownership transfer rule • Separation logic can express disjointness and sharing Person age: int Student exm: int Musician pfm: int StudentMusician
More examples Relationships between predicate arguments • axiom A(deps: d, bal: b) d + 100 < b Properties of predicate arguments E.g. The number of deposits is non-negative • axiom A(deps: d, bal: b) 0 ≤ dInclude 0 ≤ d in A predicate definitions:define x.AAccount(deps: d, bal: b) as 0 ≤ d ˄ …
More examples Axioms for aggregate structures that rely on other axioms For the Counter hierarchy:axiom cnt_non_neg: C(cnt: c) 0 ≤ c In class Account:define x.AAccount(deps: d, bal: b) as∃y x.f↦ y * y.C(cnt: d) * …axiom deps_nn: A(deps: d, bal: b) 0 ≤ d relies on Counter.cnt_non_neg Account f: Counter … Counter c: int
Observations Export/axiom information can be seen as well-behaved, operation-independent invariants of OO programs They are universal invariants – always hold Logical, not operational: cannot be violated by adding new methods (cf. class invariants) Idea is not to impose a methodology Only use exports and axioms where you really want them
MultiStar Automated tool for verification Part of EVE, the Eiffel Verification Environment Front-end for Eiffel and back-end based on jStar Back-end reasoning enhancements • Export and axiom clauses • Shared multiple inheritance (including interface inheritance, handling abstract classes and methods) Demonstration
Case study with MultiStar Gobo data structure library’s iterator hierarchy Axiom of container hierarchy: ElementAt(iter: i1, elem: e1, content: c1, iters: i) * ElementAt(iter: i2, elem: e2, content: c1, iters: i) * Replaced(iter: i1, value: e2, newcontent: c2, oldcontent: c1, iters: i) * Replaced(iter: i2, value: e1, newcontent: c3, oldcontent: c2, iters: i) Swapped(iter1: i1, iter2: i2, newcontent: c3, oldcontent: c1, iters: i)
Other work Other work in the paper: • MultiStar implementation details • Formalization, proof of soundness • Related work
In conclusion • Two new specification mechanisms: export and axiom clauses • Simple, well-behaved and powerful • Sound proof system incorporating exports and axioms, based on separation logic and APFs • Accommodates shared multiple inheritance and interfaces • Implementation: MultiStar verification tool
What about class invariants? Axioms are universal representation invariants Class invariants are properties which methods must preserve Further comparison: