Verifying Asynchronous Event-Driven Programs Using Partial Abstract Transformers (Extended Manuscript)

We address the problem of analyzing asynchronous event-driven programs, in which concurrent agents communicate via unbounded message queues. The safety verification problem for such programs is undecidable. We present in this paper a technique that combines queue-bounded exploration with a convergence test: if the sequence of certain abstractions of the reachable states, for increasing queue bounds k, converges, we can prove any property of the program that is preserved by the abstraction. If the abstract state space is finite, convergence is guaranteed; the challenge is to catch the point k_max where it happens. We further demonstrate how simple invariants formulated over the concrete domain can be used to eliminate spurious abstract states, which otherwise prevent the sequence from converging. We have implemented our technique for the P programming language for event-driven programs. We show experimentally that the sequence of abstractions often converges fully automatically, in hard cases with minimal designer support in the form of sequentially provable invariants, and that this happens for a value of k_max small enough to allow the method to succeed in practice.


Introduction
Asynchronous event-driven (AED) programming refers to a style of programming multi-agent applications. The agents communicate shared work via messages. Each agent waits for a message to arrive, and then processes it, possibly sending messages to other agents, in order to collectively achieve a goal. This programming style is common for distributed systems as well as low-level designs such as device drivers [11]. Getting such applications right is an arduous task, due to the inherent concurrency: the programmer must defend against all possible interleavings of messages between agents. In response to this challenge, recent years have seen multiple approaches to verifying AED-like programs, e.g. by delaying send actions, or temporarily bounding their number (to keep queue sizes small) [10,7], or by reasoning about a small number of representative execution schedules, to avoid interleaving explosion [5].
In this paper we consider the P language for AED programming [11]. A P program consists of multiple state machines running in parallel. Each machine has a local store, and a message queue through which it receives events from other machines. P allows the programmer to formulate safety specifications via a statement that asserts some predicate over the local state of a single machine. Verifying such reachability properties of course requires reasoning over global system behavior and is, for unbounded-queue P programs, undecidable [8].
The unboundedness of the reachable state space does not prevent the use of testing tools that try to explore as much of the state space as possible [13,3,11,6] in the quest for bugs. Somewhat inspired by this kind of approach, the goal of this paper is a verification technique that can (sometimes) prove a safety property, despite exploring only a finite fraction of that space. Our approach is as follows. Assuming that the machines' queues are the only source of unboundedness, we consider a bound k on the queue size, and exhaustively compute the reachable states R k of the resulting finite-state problem, checking the local assertion Φ along the way. We then increase the queue bound until (an error is found, or) we reach some point k max of convergence: a point that allows us to conclude that increasing k further is not required to prove Φ.
What kind of "convergence" are we targeting? We design a sequence (R k ) ∞ k=0 of abstractions of each reachability set over a finite abstract state space. Due to the monotonicity of sequence (R k ) ∞ k=0 , this ensures convergence, i.e. the existence of k max such that R K = R kmax for all K ≥ k max . Provided that an abstract state satisfies Φ exactly if all its concretizations do, we have: if all abstract states in R kmax comply with Φ, then so do all reachable concrete states of P-we have proved the property.
We implement this strategy using an abstraction function α with a finite co-domain that leaves the local state of a machine unchanged and maintains the first occurrence of each event in the queue; repeat occurrences are dropped. This abstraction preserves properties over the local state and the head of the queue, i.e. the visible (to the machine) part of the state space, which is typically sufficient to express reachability properties.
The second major step in our approach is the detection of the point of convergence of (R k ) ∞ k=0 : We show that, for the best abstract transformer Im [9,26, see Sec. 4.2], if Im(R k ) ⊆ R k , then R K = R k for all K ≥ k. In fact, we have a stronger result: under an easy-to-enforce condition, it suffices to consider abstract dequeue operations: all others, namely enqueue and local actions, never lead to abstract states in R k+1 \ R k . The best abstract transformer for dequeue actions is efficiently implementable for a given P program.
It is of course possible that the convergence condition Im(R k ) ⊆ R k never holds (the problem is undecidable). This manifests in the presence of a spurious abstract state in the image produced by Im, i.e. one whose concretization does not contain any reachable state. Our third contribution is a technique to assist users in eliminating such states, enhancing the chances for convergence. We have observed that spurious abstract states are often due to violations of simple machine invariants: invariants that do not depend on the behavior of other machines. By their nature, they can be proved using a cheap sequential analysis.
We can eliminate an abstract state (e.g. produced by Im) if all its concretizations violate a machine invariant. In this paper, we propose a domain-specific temporal logic to express invariants over machines with event queues and, more importantly, an algorithm that decides the above abstract queue invariant checking problem, by reducing it efficiently to a plain model checking problem. We have used this technique to ensure the convergence in "hard" cases that otherwise defy convergence of the abstract reachable states sequence.
We have implemented our technique for the P language and empirically evaluated it on an extensive set of benchmark programs. The experimental results support the following conclusions: (i) for our benchmark programs, the sequence of abstractions often converges fully automatically, in hard cases with minimal designer support in the form of separately dischargeable invariants; (ii) almost all examples converge at a small value of k max ; and iii) the overhead our technique adds to the bounding technique is small: the bulk is spent on the exhaustive bounded exploration itself.
Proofs and other supporting material can be found in the Appendix.

Overview
We illustrate the main ideas of this paper using an example in the P language. A machine in a P program consists of multiple states. Each state defines an entry code block that is executed when the machine enters the state. The state also defines handlers for each event type e that it is prepared to receive. A handler can either be on e do foo (executing foo on receiving e), or ignore e (dequeuing and dropping e). A state can also have a defer e declaration; the semantics is that a machine dequeues the first non-deferred event in its queue. As a result, a queue in a P program is not strictly FIFO. This relaxation is an important feature of P that helps programmers express their logic compactly [11]. Fig. 1 shows a P program named PiFl , in which a Sender (eventually) floods a Receiver's queue with Ping events. This queue is the only source of unboundedness in PiFl . A critical property for P programs is (bounded) responsiveness: the receiving machine must have a handler (e.g. on, defer, ignore) for every event arriving at the queue head; otherwise the event will come as a "surprise" and crash the machine. To prove responsiveness for PiFl , we have to demonstrate (among others) that in state Ignore it, the head of the Receiver's queue is always Ping. We cannot perform exhaustive model checking, since the set of reachable states is infinite. Instead, we will compute a conservative abstraction of this set that is precise enough to rule out Prime or Done events at the queue head in this state.
We first define a suitable abstraction function α that collapses repeated occurrences of events to each event's first occurrence. For instance, the queue Q = Prime.Prime.Prime.Done.Ping.Ping.Ping.Ping (1) will be abstracted to Q = α(Q) = Prime.Done.Ping. The finite number of possible abstract queues is 1 + 3 + 3 · 2 + 3 · 2 · 1 = 16. The abstraction preserves the head of the queue. This and the machine state is enough information to check responsiveness. We now generate the sequence R k of abstractions of the reachable states sets R k for queue size bounds k = 0, 1, 2, . . ., by computing each finite set R k , and then R k as α(R k ). The obtained monotone sequence (R k ) ∞ k=0 over a finite domain will eventually converge, but we must prove that it has. This is done by applying the best abstract transformer Im, restricted to dequeue operations (defined in Sec. 4.2), to the current set R k , and confirming that the result is contained in R k .
As it turns out, the confirmation fails for the PiFl program: k = 5 marks the first time set R k repeats, i.e. R 4 = R 5 , so we are motivated to run the convergence test. Unfortunately we find a states ∈ Im(R 5 ) \ R 5 , preventing convergence. Our approach now offers two remedies to this dilemma. One is to refine the queue abstraction. In our implementation, function α is really α p , for a parameter p that denotes the size of the prefix of the queue that is kept unchanged by the abstraction. For example, for the queue from Eq. (1) we have α 4 (Q) = Prime.Prime.Prime.Done | Ping, where | separates the prefix from the "infinite tail" of the abstract queue. This (straightforward) refinement maintains finiteness of the abstraction and increases precision, by revealing that the queue starts with three Prime events. Re-running the analysis for the PiFl program with p = 4, at k = 5 we find Im(R 5 ) ⊆ R 5 , and the proof is complete.
The second remedy to the failed convergence test dilemma is more powerful but also less automatic. Let's revert to prefix p = 0 and inspect the abstract states ∈ Im(R 5 ) \ R 5 that foils the test. We find that it features a Done event followed by a Prime event in the Receiver's queue. A simple static analysis of the Sender's machine in isolation shows that it permits no path from the send Done to the send Prime statement. The behavior of other machines is irrelevant for this invariant; we call it a machine invariant. We pass the invariant to our tool via the command line using the expression in a temporal-logic like notation called QuTL (Sec. 5.1), where G universally quantifies over all queue entries. Our tool includes a QuTL checker that determines that every concretization ofs violates property (2), concluding thats is spurious and can be discarded. This turns out to be sufficient for convergence.

Queue-(Un)Bounded Reachability Analysis
Communicating Queue Systems. We consider P programs consisting of a fixed and known number n of machines communicating via event passing through unbounded FIFO queues. 3 For simplicity, we assume the machines are created at the start of the program; dynamic creation at a later time can be simulated by having the machine ignore all events until it receives a special creation event.
We model such a program as a communicating queue system (CQS). Formally, given n ∈ N, a CQS P n is a collection of n queue automata (QA) A QA consists of a finite queue alphabet Σ shared by all QA, a finite set L i of local states, a finite set Act i of action labels, a finite set and an initial local state I i ∈ L i . An action label act ∈ Act i is of the form act ∈ {deq, loc}, denoting an action internal to P i (no other QA involved) that either dequeues an event (deq), or updates its local state (loc); or act = !(e, j), for e ∈ Σ, j ∈ {1, . . . , n}, denoting a transmission, where P i (the sender ) adds event e to the end of the queue of P j (the receiver ).
The individual QA of a CQS model machines of a P program; hence we refer to QA states as machine states. A transmit action is the only communication mechanism among the QA.

Semantics.
A machine state m of a QA is of the form ( , Q) ∈ L × Σ * ; state m I = ( I , ε) is initial. We define machine transitions corresponding to internal actions as follows (transmit actions are defined later at the global level): . . , ( I n , ε) is initial. We extend the machine transition relation → to states as follows: if there exists i ∈ {1, . . . , n} such that one of the following holds: (transmission) there exists j ∈ {1, . . . , n} and e ∈ Σ such that: The execution model of a CQS is strictly interleaving. That is, in each step, one of the two above transitions (internal) or (transmission) is performed for a nondeterministically chosen machine i.
Queue-bounded and queue-unbounded reachability. Given a CQS P n , a state s = ( 1 , Q 1 ), . . . , ( n , Q n ) , and a number k, the queue-bounded reachability problem (for s and k) determines whether s is reachable under queue bound k, i.e. whether there exists a path s 0 → s 1 . . . → s z such that s 0 = s I , s z = s, and for i ∈ {0, . . . , z}, all queues in state s i have at most k events. Queue-bounded reachability for k is trivially decidable, by making enqueue actions for queues of size k blocking (the sender cannot continue), which results in a finite state space. We write R k = {s : s is reachable under queue bound k}.
Queue-bounded reachability will be used in this paper as a tool for solving our actual problem of interest: Given a CQS P n and a state s, the Queue-UnBounded reachability Analysis (QUBA) problem determines whether s is reachable, i.e. whether there exists a (queue-unbounded) path from s I to s. The QUBA problem is undecidable [8]. We write R (= k∈N R k ) for the set of reachable states.

Convergence via Partial Abstract Transformers
In this section, we formalize our approach to detecting the convergence of a suitable sequence of observations about the states R k reachable under k-bounded semantics. We define the observations as abstractions of those states, resulting in sets R k . We then investigate the convergence of the sequence (R k ) ∞ k=0 .

List Abstractions of Queues
Our abstraction function applies to queues, as defined below. Its action on machine and system states then follows from the hierarchical design of a CQS. Let |Q| denote the number of events in Q, and Q[i] the ith event in Q (0 ≤ i < |Q|).
Def. 1 For a parameter p ∈ N, the list abstraction function α p : Σ * → Σ * is defined as follows: Intuitively, α p abstracts a queue by leaving its first p events unchanged (an idea also used in [16]). Starting from position p it keeps only the first occurrence of each event e in the queue, if any; repeat occurrences are dropped. 4 The preservation of existence and order of the first occurrences of all present events motivates the term list abstraction. An alternative is an abstraction that keeps only the set (not: list) of queue elements from position p, i.e. it ignores multiplicity and order. This is by definition less precise than the list abstraction and provided no efficiency advantages in our experiments. An abstraction that keeps only the queue head proved cheap but too imprecise. The motivation for parameter p is that many protocols proceed in rounds of repeating communication patterns, involving a bounded number of message exchanges. If p exceeds that number, the list abstraction's loss of information may be immaterial.
We write an abstract queue Q = α p (Q) in the form pref | suff s.t. p = |pref |, and refer to pref as Q's prefix (shared with Q), and suff as Q's suffix.
Discussion. The abstract state space is finite since the queue prefix is of fixed size, and each event in the suffix is recorded at most once (the event alphabet is finite). The sets of reachable abstract states grow monotonously with increasing queue size bound k, since the sets of reachable concrete states do: Finiteness and monotonicity guarantee convergence of the sequence of reachable abstract states.
We say the abstraction function α p respects a property of a state if, for any two α p -equivalent states (see Ex. 2), the property holds for both or for neither. Function α p respects properties that refer to the local-state part of a machine, and to the first p+1 events of its queue (which are preserved by α p ). In addition, the property may look beyond the prefix and refer to the existence of events in the queue, but not their frequency or their order after the first occurrence.
The rich information preserved by the abstraction (despite being finite-state) especially pays off in connection with the defer feature in the P language, which allows machines to delay handling certain events at the head of a queue [11]. The machine identifies the first non-deferred event in the queue, a piece of information that is precisely preserved by the list abstraction (no matter what p).
As a special case, RE p (ε) = ε and so γ p (ε) = L(ε) = {ε} for the empty queue. We extend γ p to act on abstract (machine or global) states in a way analogous to the extension of α p , by moving it inside to the queues occurring in those states.

Abstract Convergence Detection
Recall that finiteness and monotonicity of the sequence (R k ) ∞ k=0 guarantee its convergence, so nothing seems more suggestive than to compute the limit. We summarize our overall procedure to do so in Alg. 1. The procedure iteratively increases the queue bound k and computes the concrete and (per α p -projection) the abstract reachability sets R k and R k . If, for some k, an error is detected, the procedure terminates (Lines 4-5; in practice implemented as an on-the-fly check).
1: compute R0; R0 := αp(R0) 2: for k := 1 to ∞ do 3: compute R k ; R k := αp(R k ) 4: if ∃r ∈ R k : r |= Φ then 5: return "error reachable with queue bound k" 6: if |R k | = |R k−1 | then 7: T := (αp • Im deq • γp)(R k ) partial best abstract transformer 8: if T ⊆ R k then 9: return "safe for any queue bound" The key of the algorithm is reflected in Lines 6-9 and is based on the following idea (all claims are proved as part of Thm. 4 below). If the computation of R k reveals no new abstract states in round k (Line 6; by monotonicity, "same size" implies "same sets"), we apply the best abstract transformer [9,26] Im := α p • Im → • γ p to R k : if the result is contained in R k , the abstract reachability sequence has converged. However, we can do better: we can restrict the successor function Im → of the CQS to dequeue actions, denoted Im deq in Line 7. The ultimate reason is that firing a local or transmit action on two α p -equivalent states r and s results again in α p -equivalent states r and s . This fact does not hold for dequeue actions: the successors r and s of dequeues depend on the abstracted parts of r and s, resp., which may differ and become "visible" during the dequeue (e.g. the event behind the queue head moves into the head position). Our main result therefore is: if R k = R k−1 and dequeue actions do not create new abstract states (Lines 7 and 8), sequence (R k ) ∞ k=0 has converged: Thm. 4 If R k = R k−1 and T ⊆ R k , then for any K ≥ k, R K = R k .
If the sequence of reachable abstract states has converged, then all reachable concrete states (any k) belong to γ p (R k ) (for the current k). Since the abstraction function α p respects property Φ, we know that if any reachable concrete state violated Φ, so would any other concrete state that maps to the same abstraction. However, for each abstract state in R k , Line 4 has examined at least one state r in its concretization; a violation was not found. We conclude: Cor. 5 Line 9 of Alg. 1 correctly asserts that no reachable concrete state of the given CQS violates Φ.
The corollary (along with the earlier statement about Lines 4-5) confirms the partial correctness of Alg. 1. The procedure is, however, necessarily incomplete: if no error is detected and the convergence condition in Line 8 never holds, the for loop will run forever.
We conclude this part with two comments. First, note that we do not compute the sets R k as reachability fixpoints in the abstract domain (i.e. the domain of α p ). Instead, we compute the concrete reachability sets first, and then obtain the R k via projection (Line 1). The reason is that the projection gives us the exact set of abstractions of reachable concrete states, while an abstract fixpoint likely overapproximates (for instance, the best abstract transformer from Line 7 does) and loses precision. Note that a primary motivation for computing abstract fixpoints, namely that the concrete fixpoint may not be computable, does not apply here: the concrete domains are finite, for each k.
Second, we observe that this projection technique comes with a cost: sequence (R k ) ∞ k=0 may stutter at intermediate moments: . The reason is that R k+3 is not obtained as a functional image of R k+2 , but by projection from R k+3 . As a consequence, we cannot short-cut the convergence detection by just "waiting" for (R k ) ∞ k=0 to stabilize, despite the finite domain.

Computing Partial Best Abstract Transformers
Recall that in Line 7 we compute The line applies the best abstract transformer, restricted to dequeue actions, to R k . This result cannot be computed as defined in (5), since γ p (R k ) is typically infinite. However, R k is finite, so we can iterative overr ∈ R k , and little information is actually needed to determine the abstract successors ofr. The "infinite fragment" ofr remains unchanged, which makes the action implementable. Formally, letr = ( , Q) with Q = e 0 e 1 . . . e p−1 | e p e p+1 . . . e z−1 . To apply a dequeue action tor, we first perform local-state updates on as required by the action, resulting in . Now consider Q. The first suffix event, e p , moves into the prefix due to the dequeue. We do not know whether there are later occurrences of e p before or after the first suffix occurrences of e p+1 . . . e z−1 . This information determines the possible abstract queues resulting from the dequeue. To compute the exact best abstract transformer, we enumerate these possibilities:

Abstract Queue Invariant Checking
The abstract transformer function in Sec. 4 is used to decide whether sequence (R k ) ∞ k=0 has converged. Being an overapproximation, the function may generate spurious states: they are not reachable, i.e. no concretization of them is. Unfortunate for us, spurious abstract states always prevent convergence.
A key empirical observation is that concretizations of spurious abstract states often violate simple machine invariants, which can be proved from the perspective of a single machine, while collapsing all other machines into a nondeterministically behaving environment. Consider our example from Sec. 2 for p = 0. It fails to converge since Line 7 generates an abstract states that features a Done event followed by a Prime event in the Receiver's queue. A light-weight static analysis proves that the Sender's machine permits no path from the send Done to the send Prime statement. Since every concretization ofs features a Done followed by a Prime event, the abstract states is spurious and can be eliminated.
Our tool assists users in discovering candidate machine invariants, by facilitating the inspection of states in T \ R k (which foil the test in Line 8). We discharge such invariants separately, via a simple sequential model-check or static analysis. In the section we focus on the more interesting question of how to use them. Formally, suppose the P program comes with a queue invariant I, i.e. an invariant property of concrete queues. The abstract invariant checking problem is to decide, for a given abstract queue Q, whether every concretization of Q violates I; in this case, and this case only, an abstract state containing Q can be eliminated. In the following we define a language QuTL for specifying concrete queue invariants (5.1), and then show how checking an abstract queue against a QuTL invariant can be efficiently solved as a model checking problem (5.2).

Queue Temporal Logic (QuTL)
Our logic to express invariant properties of queues is a form of first-order lineartime temporal logic. This choice is motivated by the logic's ability to constrain the order (via temporal operators) and multiplicity of queue events, the latter via relational operators that express conditions on the number of event occurrences.
Queue Relational Expressions (QuRelE). These are of the form #e c, where e ∈ Σ (queue alphabet), ∈ {<, ≤, =, ≥, >}, and c ∈ N is a literal natural number. The value of a QuRelE is defined as the Boolean where |·| denotes set cardinality and is interpreted as the standard integer arithmetic relational operator. In the following we write Q[i →] (read: "Q from i") for the queue obtained from queue Q by dropping the first i events.
Def. 6 (Syntax of QuTL) The following are QuTL formulas: false and true.
-E, for a queue relational expression E.
The set QuTL is the Boolean closure of the above set of formulas.
Def. 7 (Concrete semantics of QuTL) Concrete queue Q satisfies QuTL formula φ, written Q |= φ, depending on the form of φ as follows.
for a queue relational expression E, Satisfaction of Boolean combinations is defined as usual, e.g. Q |= ¬φ iff Q |= φ.
For instance, formula #e ≤ 3 is true exactly for queues containing at most 3 e's, and formula G(#e ≥ 1) is true of Q iff Q is empty or its final event (!) is e. See App. B for more examples. Algorithmically checking whether a concrete queue Q satisfies a QuTL formula φ is straightforward, since Q is of fixed size and straight-line. The situation is different with abstract queues. Our motivation here is to declare that an abstract queue Q violates a formula φ if all its concretizations (Def. 3) do: under this condition, if φ is an invariant, we know Q is not reachable. Equivalently: Def. 8 (Abstract semantics of QuTL) Abstract queue Q satisfies QuTL formula φ, written Q |= p φ, if some concretization of Q satisfies φ: For example, we have bb | ba |= 2 G(a ⇒ G ¬b) since for instance bbba ∈ γ 2 (bb | ba) satisfies the formula. See App. B for more examples.

Abstract QuTL Model Checking
A QuTL constraint is a QuTL formula without Boolean connectives. We first describe how to model check against QuTL constraints, and come back to Boolean connectives at the end of Sec. 5.2.
Model checking an abstract queue Q against a QuTL constraint φ, i.e. checking whether some concretization of Q satisfies φ, can be reduced to a standard model checking problem over a  We call a path through M complete if it ends in the right-most state s z of M (green in Fig. 2). The labeling function extends to paths via L(s i → . . . → s j ) = L(s i ) · . . . · L(s j ). This gives rise to the following characterization of γ p (Q): Lem. 9 Given abstract queue Q over alphabet Σ, let M = (S, T, L) be its LTS.
Cor. 10 Let Q and M as in Lem. 9, and φ a QuTL constraint. Then the following are equivalent.
2. There exists a complete path π from s 0 in M such that π |= p φ.
Given an abstract queue Q, its LTS M , and a QuTL constraint φ, our abstract queue model checking algorithm is based on Cor. 10: we need to find a complete path from s 0 in M that satisfies φ. This is similar to standard model checking against existential temporal logics like ECTL, with two particularities: First, paths must be complete. This poses no difficulty, as completeness is suffix-closed: a path ends in s z iff any suffix does. This implies that temporal reductions on QuTL constraints work like in standard temporal logics. For example: there exists a complete path π from s 0 in M such that π |= p X φ iff there exists a complete path π from some successor s 1 of s 0 such that π |= p φ.
Second, we have domain-specific atomic (non-temporal) propositions. These are accommodated as follows, for an arbitrary start state s ∈ S: ∃π : π from s complete and π |= p e (for e ∈ Σ): this is true iff e ∈ L(s), as is immediate from the Q |= e case in Def. 7. ∃π : π from s complete and π |= p #e > c (for e ∈ Σ, c ∈ N): this is true iff the number of states reachable from s labeled e is greater than c, or there exists a state reachable from s labeled with e that has a self-loop. The other relational expressions #e c are checked similarly.
Boolean connectives. Let now φ be a full-fledged QuTL formula. We first bring it into negation normal form, by pushing negations inside, exploiting the usual dualities ¬ X = X ¬, ¬ F = G ¬, and ¬ G = F ¬. The subset ∈ {<, ≤, ≥, >} of the queue relational expressions is semantically closed under negation; "¬=" is replaced by "> ∨ <". A path π from s satisfies ¬e (for e ∈ Σ) iff L(s) = {e}: this condition states that either L(s) = ε, or there exists some label other than e in L(s), so the existential property ¬e holds.
Disjunctions are handled by distributing |= p over them: What remains are conjunctions. The existential flavor of |= p implies that |= p does not distribute over them; see Ex. 13 in App. B.1. Suppose we ignore this and replace a check of the form Q |= p φ 1 ∧ φ 2 by the weaker check Q |= p φ 1 ∧ Q |= p φ 2 , which may produce false positives. Now consider how we use these results: if Q |= p φ holds, we decide to keep the state containing the abstract queue. False positives during abstract model checks therefore may create extra work, but do not introduce unsoundness. In summary, our abstract model checking algorithm soundly approximates conjunctions, but remains exact for the purely disjunctive fragment of QuTL.

Empirical Evaluation
We implemented the proposed approaches in C# atop the bounded model checker PTester [11], an analysis tool for P programs. PTester employs a bounded exploration strategy similar to Zing [4]. We denote by Pat the implementation of Alg. 1, and by Pat+I the version with queue invariants ("Pat+ Invariants").
A detailed introduction to tool design and implementation is available online [22].
Experimental Goals. We evaluate the approaches against the following questions: Q1. Is Pat effective: does it converge for many programs? for what values of k? Q2. What is the impact of the QuTL invariant checking?
We conduct two types of experiments: (i) we run Pat on each benchmark to empirically answer Q1; (ii) we run Pat+I on the examples which fail to verify in (i) to answer Q2. All experiments are performed on a 2.80 GHz Intel(R) Core(TM) i7-7600 machine with 8 GB memory, running 64-bit Windows 10. The timeout is set to 3600sec (1h); the memory limit to 4 GB.
Results. Table 1 shows that Pat converges on almost all safe examples (and successfully exposes the bugs for unsafe ones). Second, in most cases, the k max where convergence was detected is small, 5 or less. This is what enables the use of this technique in practice: the exploration space grows fast with k, so early convergence is critical. Note that k max is guaranteed to be the smallest value for which the respective example converges. If convergent, the verification succeeded fully automatically: the queue abstraction prefix parameter p is incremented in a loop whenever the current value of p caused a spurious abstract state. The German protocol does not converge in reasonable time. In this case, we request minimal manual assistance from the designer. Our tool inspects spurious abstract states, compares them to actually reached abstract states, and suggests candidate invariants to exclude them. We describe the process of invariant discovery, and why and how they are easy to prove, in [22].
The following table shows the invariants that make the German protocol converge, and the resulting times and memory consumption. The invariant states that there is always at most one exclusive request and at most one shared request in the Server or Client machine's queue.
Performance Evaluation. We finally consider the following question: To perform full verification, how much overhead does Pat incur compared to PTester? We iteratively run PTester with a queue bound from 1 up to k max (from Table 1). The figure on the right compares the running times of Pat and PTester. We observe that the difference is small, in all cases, suggesting that turning PTester into a full verifier comes with little extra cost. Therefore, as for improving Pat's scalability, the focus should be on the efficiency of the R k computation (Line 3 in Alg. 1). Techniques that lend themselves here are partial order reduction [2,27] or symmetry reduction [28]. Note that our proposed approach is orthogonal to how these sets are computed.

Related Work
Automatic verification for asynchronous event-driven programs communicating via unbounded FIFO queues is undecidable [8], even when the agents are finitestate machines. To sidestep the undecidability, various remedies are proposed. One is to underapproximate program behaviors using various bounding techniques; examples include depth- [17] and context-bounded analysis [25,19,20], delay-bounding [13], bounded asynchrony [15], preemption-bounding [23], and phase-bounded analysis [6,3]. It has been shown that most of these bounding techniques admit a decidable model checking problem [25,19,20] and thus have been successfully used in practice for finding bugs.
Gall et. al proposed an abstract interpretation of FIFO queues in terms of regular languages [16]. While our works share some basic insights about taming queues, the differences are fundamental: our abstract domain is finite, guaranteeing convergence of our sequence. In [16] the abstract domain is infinite; they propose a widening operator for fixpoint computation. More critically, we use the abstract domain only for convergence detection; the set of reachable states returned is in the end exact. As a result, we can prove and refute properties but may not terminate; [16] is inexact and cannot refute but always returns.
Several partial verification approaches for asynchronous message-passing programs have been presented recently [10,5,7]. In [5], Bakst et al. propose canonical sequentialization, which avoids exploring all interleavings by sequentializing concurrent programs. Desai et al [10] propose an alternative way, namely by prioritizing receive actions over send actions. The approach is complete in the sense that it is able to construct almost-synchronous invariants that cover all reachable local states and hence suffice to prove local assertions. Similarly, Bouajjani et al. [7] propose an iterative analysis that bounds send actions in each interaction phase. It approaches the completeness by checking a program's synchronizability under the bounds. Similar to our work, the above three works are sound but incomplete. An experimental comparison against the techniques reported in [10,7] fails due to the unavailability of a tool that implements them. While tools implementing these techniques are not available [10,7], a comparison based on what is reported in the papers suggests that our approach is competitive in both performance and precision.
Our approach can be categorized as a cutoff detection technique [12,1,14,27]. Cutoffs are, however, typically determined statically, often leaving them too large for practical verification. Aiming at minimal cutoffs, our work is closer in nature to earlier dynamic strategies [18,21], which targeted different forms of concurrent programs. The generator technique proposed in [21] is unlikely to work for P programs, due to the large local state space of machines.

Conclusion
We have presented a method to verify safety properties of asynchronous eventdriven programs of agents communicating via unbounded queues. Our approach is sound but incomplete: it can both prove (or, by encountering bugs, disprove) such properties but may not terminate. We empirically evaluate our method on a collection of P programs. Our experimental results showcase our method can successfully prove the correctness of programs; such proof is achieved with little extra resource costs compared to plain state exploration. Future work includes an extension to P programs with other sources of unboundedness than the queue length (e.g. messages with integer payloads).
Lem. 6 Given R k = R k−1 and (R k ) ⊆ R k , we have for any K ≥ k, R K = R k .
Proof : by induction on K. The claim holds for K = k. Now suppose To this end, let a ∈ R K+1 , i.e. a = α p (s a ) for some s a ∈ R K+1 . We show: for all states s along the path π that reaches s a , α p (s) ∈ R K ; call this claim (*). In particular, then, a = α p (s a ) ∈ R K .
To show (*), we induct on the length of path π. The initial state belongs to R l for every l, so its abstraction belongs to R K . Let now s along π be such that α p (s) ∈ R K . Since R K = R k , we have s ∈ γ p (R k ). By Eq. (10), the successor s of s along π satisfies α p (s ) ∈ (R k ) ⊆ R k = R K .
Proof of Thm. 4: From R k = R k−1 , T ⊆ R k and Lem. 5 we conclude (R k ) ⊆ R k . From R k = R k−1 , (R k ) ⊆ R k and Lem. 6 we conclude the claim in Thm. 4.

A.2 Construction of the LTS for Abstract Queue Q
This construction is required for Lem. 9 (App. A.3). We formalize it as follows. If Q = ε, we let S = {s 0 }, T = ∅, L(s 0 ) = ε. Otherwise, let Q = e 0 . . . e p−1 | e p . . . e z−1 . We first define two separate LTS, M p and M s , for prefix and suffix, resp., and then conjoin them to get M : A.3 Proof of Lem. 9 Lem. 9 Given abstract queue Q over alphabet Σ, let M = (S, R, L) be its LTS.
γ p (Q) = {L(L(π)) ∈ 2 Σ * | π is a complete path from s 0 in M } . -If a is in the prefix of Q, i.e. the suffix of Q is empty, we have {L(L(t)) ∈ 2 Σ * | t is a complete path from s 0 in M T } · {a} where "D3" refers to Def. 3, and "IH" denotes the induction hypothesis.
Since M equals M T extended by an edge to an a-labeled state, with a unique complete path, Eq. (13) follows. -If a is in the suffix of Q, then let Σ s be the set of all suffix symbols of Q (in particular, a ∈ Σ s ). Satisfaction relation Meaning Q |= #e ≤ 3 Q contains at most 3 e's. Q |= G(e 1 ⇒ G ¬e 2 ) In Q, e 1 is never (eventually) followed by e 2 . Q |= F(#e < 2) Q is non-empty. Q |= G(#e ≥ 2) Q is empty. Q |= G(#e ≥ 1) Q is empty or its tail event is an e.

Ex. 11
Here are some examples of abstract (non-)satisfaction. As indicated, these assume p = 2, i.e. the first two queue events (if any) are unabstracted. Again, a ⇒ b abbreviates ¬a ∨ b.
bb | ba |= 2 G(a ⇒ G ¬b) since there is a concretization, for instance bbba, that satisfies the formula.
since the violation is caused by the prefix of queue (ac), so all concretizations violate this formula.