Generating Rely-Guarantee Conditions with the Conditional-Writes Domain
Abstract interpretation has been shown to be a promising technique for the thread-modular verification of concurrent programs. Central to this is the generation of interferences, in the form of rely-guarantee conditions, conforming to a user-chosen structure. In this work, we introduce one such structure called the conditional-writes domain, designed for programs where it suffices to establish only the conditions under which particular variables are written to by each thread. We formalise our analysis within a novel abstract interpretation framework that is highly modular and can be easily extended to capture other structures for rely-guarantee conditions. We formalise two versions of our approach and evaluate their implementations on a simple programming language.
💡 Research Summary
The paper addresses a central challenge in thread‑modular verification of concurrent programs: the automatic generation of interference information in the form of rely‑guarantee conditions. Traditional abstract‑interpretation frameworks for concurrency treat pre‑state and post‑state variables uniformly, which makes it difficult to express constraints that differ between the two. To overcome this limitation, the authors introduce a new class of abstract domains called interference domains and instantiate it with a concrete example they call the conditional‑writes domain.
In the conditional‑writes domain each program variable v is mapped to an abstract element D(v) that over‑approximates the set of states in which v may be written. Thus an element i∈I is a function i:V→D, where V is the set of program variables. The domain therefore captures statements such as “x may be assigned only when the state satisfies (z=0 ∧ r=0)”. The domain is equipped with three essential operations:
-
transitions: given a state abstract element d∈D and an assignment a, it returns an interference element i that records the write‑condition for the variable being assigned. This operation extracts from d the precise pre‑conditions under which the assignment can occur.
-
stabilise: given an interference element i (interpreted as a rely condition) and a state element d, it produces a new state element that over‑approximates all states reachable in one step of i from any state in d. In other words, it applies the interference of other threads to the current thread’s abstract state.
-
close: computes the transitive closure of an interference element, collapsing multi‑step transitions into a single element. Using close allows the analysis to account for arbitrarily many interference steps with a single stabilise call, at the cost of an extra closure computation.
The authors formalise two variants of their analysis. The first variant computes the closure of each guarantee condition before stabilising, thereby handling any number of interference steps in one pass. The second variant omits the closure and repeatedly applies stabilise, which can be cheaper when the closure would be large. Both variants are proved sound with respect to the concrete semantics.
To demonstrate the approach, the paper defines a tiny imperative language (assignments, conditionals, while loops, skip) and a simple constant abstract state domain that maps variables to concrete constant values. A small example program with two threads illustrates the workflow:
- Thread T0 writes r←0, then conditionally writes x←0 when z=0, and finally copies x into r.
- Thread T1 conditionally writes x←1 when z=1.
The analysis first computes a proof outline for each thread using the constant domain, then derives guarantee conditions via transitions. For T0 the guarantee maps r to ⊤ (always writable), x to the condition (r=0 ∧ z=0), and z to ⊥ (never written). After converting guarantees to rely conditions for the other thread and applying close, the analysis obtains a transitive rely that states x may be written whenever z=0, regardless of r. Stabilising T1’s proof outline with this rely yields reachable states that respect the interference, and a guarantee for T1 that x is only written when z=1. The two guarantees are then combined to form a global rely‑guarantee pair, and a fixed point is reached after a second iteration, proving that r=0 holds at termination.
The paper emphasizes the modularity of the framework: the interference domain is parameterised by any abstract state domain D, allowing the technique to be reused with numeric, pointer, or relational domains. The set of variables V_t over which each thread’s rely is defined can be tuned for precision or efficiency, and a precision parameter N controls how many one‑step transitions are considered during stabilisation.
In the related‑work discussion the authors compare their approach to prior thread‑modular analyses that use numeric abstract domains with primed variables, highlighting that the conditional‑writes domain can express pre‑post distinctions without duplicating variables. They also note that their framework can be extended to capture other interference patterns such as read‑write dependencies or memory‑order constraints.
Overall, the contribution is a clean, extensible abstract‑interpretation framework that isolates the “what may be written under what condition” information in a dedicated interference domain. By doing so, it reduces the need to track exact values of written variables, leading to simpler and often more scalable verification of concurrent programs while preserving soundness.
Comments & Academic Discussion
Loading comments...
Leave a Comment