C: A Verification Framework For Concurrent Imperative Programs
C: A Verification Framework For Concurrent Imperative Programs
138
erties of seL4 to the C implementation [Klein et al. 2010; and potentially a multicore variant of seL4. Our framework
Murray et al. 2012]. The framework, however, lacks the abil- assumes that the granularity of interleaving is that of C
ity to reason about concurrency. instructions; porting the guarantees down to executable code
We extend S IMPL with support for shared-variable con- and weak memory architectures is not in the scope of this
currency, following the foundational Owicki-Gries (OG) paper.
method [Owicki and Gries 1976]. OG has been for- All our Isabelle/HOL formalisations and the case studies
malised in Isabelle/HOL’s library in the Hoare-Parallel the- are available online [COMPLX].
ory [Prensa Nieto 2002] for a simple high-level while-
language IMP. We chose OG over more recent variants 2. Background
(e.g. Rely-Guarantee [Jones 1983], Concurrent Separation In this section, we present existing work that our paper
Logic [OHearn 2007]) for the simplicity of OG logic combines and extends. The first section presents S IMPL,
and its suitability to reason about potentially-racy high- an existing formalisation of sequential imperative programs
performance shared-variable system code: we previously in Isabelle/HOL (and the existing infrastructure to verify
successfully used it for a model-level verification of the in- C code). The second presents Hoare-Parallel, an existing
terruptible eChronos embedded OS [Andronick et al. 2015, formalisation of OG for a simple while-language in Is-
2016]. The OS provides an API to applications for synchro- abelle/HOL. Our work consolidates those two components
nisation and locking, but the OS code itself shares racy mem- to create a language that provides a basis for reasoning about
ory state with interrupt handlers1 . In this previous work, we concurrent C code in Isabelle/HOL.
used Hoare-Parallel’s formalisation of OG and we demon-
strated how the well-known explosion of verification con- 2.1 Verification of C in Isabelle/HOL
ditions of the OG method can be efficiently handled by the As mentioned in the introduction, S IMPL allows embedding
powerful automation of modern theorem provers and by the of real programming languages into Isabelle/HOL, and is
careful modelling of controlled interleaving. We now want sufficiently expressive to model a substantial subset of C
to push our proofs down to guarantees about the C imple- features. S IMPL can be used directly for reasoning about
mentation, which is the motivation for the work presented C code and it has indeed been used directly in the verifi-
here. cation of LEDA’s [Mehlhorn and Näher 1999] shortest path
Our contributions are the following: checker [Rizkallah 2014].
• We propose the language C OMPLX as an extension of A far more common verification approach though is using
S IMPL with support for parallel composition and syn- the C-to-Isabelle parser [Tuch et al. 2007] which converts a
chronisation, and we define its concurrent semantics. We large subset of C99 code into low-level S IMPL code. S IMPL
largely reuse S IMPL’s existing infrastructure to facilitate and the C-to-Isabelle parser together provide an established
the port of existing verifications that use S IMPL (sec- infrastructure for the verification of sequential C programs in
tion 3). Isabelle/HOL. They have been used in the verification of the
seL4 microkernel which is written in C [Klein et al. 2010]
• We define a practical OG-based logic, inspired by Hoare-
and in several other C verification projects [Amani et al.
Parallel, and a VCG to facilitate semi-automated proof 2016; Murray et al. 2012; Noschinski et al. 2014].
using the logic (section 4).
• We prove our logic sound with respect to the semantics,
Syntax S IMPL provides the usual imperative language
constructs, including functions, variable assignment, se-
ensuring that proofs using the logic are true guarantees
quential composition, conditional statements, while loops,
about the execution of the program (section 5).
and exceptions. S IMPL has no expression language of its
• Finally, we present a case-study demonstrating the use own; expressions are shallowly embedded. The notion of
and practicality of this framework for the verification of state is also generic and left for instantiation; it is defined as
concurrent imperative programs (section 6). an Isabelle record of local and global variables (variables are
• As part of the examples, we demonstrate how we support then simply functions on the state). The C-to-Isabelle parser
concurrent function calls, including a technique to handle only supports side-effect-free expressions, modelled as Is-
arguments passing and local variables. abelle/HOL expressions, and it instantiates the state space
to C memory states. The following is a summary of S IMPL
With additional work, the existing infrastructure around syntactic forms, where e represents an expression:
S IMPL, including the C-to-Isabelle parser, can be updated to
enable reasoning about a significant subset of concurrent C c = Skip | v := e | c1 ; ; c2 | IF e THEN c1 ELSE c2 FI
code in Isabelle/HOL. This would open up the applicability | WHILE e DO c OD | TRY c1 CATCH c2 END
to several existing codebases, including the eChronos OS, | Throw | Call n | DynCom cs | Guard f g c
1 Preventing races would require disabling interrupts, resulting in increases The DynCom cs statement is a dynamic (state depen-
of latency unacceptable for such real-time systems. dent) command that takes as argument cs which is a func-
139
tion from states to commands. It is used in C verification to 2.2 Verification of Concurrent Code in Isabelle/HOL
encode argument passing and scoping in function calls. The Hoare logic may be used to prove that a thread in a concur-
Guard f g c statement throws the fault f if the condition g rent program is locally correct, i.e. that it is correct under a
is false and executes c otherwise. It is used in C verifica- sequential interpretation of its semantics without interleav-
tion to encode certain correctness conditions ensuring that ing of external commands. In order to prove that it is correct
the C program does not exhibit undefined behaviour (e.g. in a concurrent setting, we have to additionally prove that it
division by zero). Call just takes the name of the function is globally correct, i.e. that is is still correct considering all
being called. possible interleavings with other threads in the system.
The Owicki-Gries [Owicki and Gries 1976] method for
Semantics Computations in S IMPL are described by sev- the verification of shared-variable concurrent programs ex-
eral equivalent models, including big- and small-step seman- tends the proof method for sequential correctness with the
tics. Here we are interested in the small-step semantics, as concept of interference freedom: each thread is first proved
we want to model the fine-grain interleaving of concurrent to be locally correct and then each atomic command in each
programs. thread is proved to not interfere with (i.e. invalidate) the local
The small-step semantics is represented by statements of correctness proof of another thread in parallel. If the proof of
the form Γ ` hc, si → hc0 , s0 i that read as: program c in state local correctness for a command c requires a pre-condition
s takes a step to program c0 and the updated state s0 under P , and c may be interleaved with another command c0 whose
the procedure environment Γ which maps function names pre-condition is P 0 , then in order to show interference free-
to function bodies. Both s and s0 are extended states: they dom, we show that {P 0 ∧P } c0 {P } holds, i.e. that P remains
are either Normal states, representing typical execution flow true after being interleaved with c0 .
(including exception handling), or Stuck states, generated In order to satisfy the requirements for interference free-
by calls to non-existent procedures, or Fault states, gener- dom over all threads in a system, it is necessary to store these
ated by failed Guard statements. For normal program states, intermediate assertions. Unlike for a sequential program, we
s = Normal x, the semantics is as expected; whereas in may require post-conditions to be arbitrarily stronger than
cases s = Stuck or s = Fault f we may only transform c to the weakest pre-condition implied by the Hoare logic. For
Skip with s0 = s. this reason, we need to fully annotate the concurrent pro-
Exceptions are used to represent abrupt termination — gram with intermediate assertions in order to verify its cor-
function calls and loops are wrapped in a try-catch block and rectness relative to other threads in the system, in contrast to
the C statements return, break, and continue are imple- a sequential program, for which these properties may largely
mented by assigning appropriate value to an auxiliary vari- be automatically derived and discarded once used.
able and raising an exception with Throw . The exception is Hoare-Parallel [Prensa Nieto 2002] is a formal reason-
caught by CATCH , mimicking an abrupt termination of the ing framework in Isabelle/HOL for a simple concurrent
TRY block. language, including a formalisation of OG. The language
consists of assignment, sequential composition, condition-
Verification Specifications for S IMPL programs are given als, loops, and two additional statements for concurrency:
as Hoare triples, where pre-conditions and post-conditions Parallel [ac1 ..acn ] and Await b c. The execution is mod-
are stated by Isabelle expressions. The S IMPL environment elled through a small-step semantics; an await statement can
provides a VCG for partial correctness that converts those only do a step if its boolean guard b is true, in which case
Hoare triples to a set of higher-order formulas that are eas- its body c is executed atomically; a step of a parallel com-
ier to reason about. The Hoare triples are represented by position of programs is a step of any of its thread that is not
statements of the form Γ `/F P c Q, A, where P is the blocked on an await. Hoare-Parallel’s abstract syntax is de-
pre-condition, Q is the post-condition for normal termina- fined using the following mutually recursive datatype:
tion, A is the abrupt-condition for abrupt termination2 , and
F is the set of faults allowed. A soundness proof guarantees
the safe use of the Hoare logic instead of directly reasoning ac = AnnSeq ac ac | AnnBasic r f | AnnCond b ac ac
about the semantics: it states that if such a Hoare triple is | AnnWhile r b r ac | AnnAwait r b c
established, then all final states reached through the execu- and
tion of the command (according to the semantics) from an c= Parallel [ac..ac] | Seq c c | Basic f | Cond b c c
initial state that satisfies the pre-condition, will satisfy the | While b r c
post-condition and the abrupt-condition.
The outer layer c performs sequential actions or initiates
2 Using Schirmer’s [Schirmer 2006] terminology, we refer to post-
a parallel composition, and the inner layer ac within the
conditions for abrupt-termination due to uncaught exceptions as abrupt- parallel composition expresses a thread, with each action
conditions. annotated with an assertion r.
140
COBEGIN . . . COEND is used as syntactic sugar uations arise that neither S IMPL nor the Hoare-Parallel for-
for Parallel . Throughout the paper we reuse the Hoare- malisations had to deal with. For instance, we have to decide
Parallel’s Parallel concrete syntax for C OMPLX. how a parallel program shall behave in the case when one
of its threads raises an uncaught exception. In this case we
3. C OMPLX: Syntax and Semantics allow the parallel program to stop all other threads and exit
Recall that the aim of C OMPLX is to enrich S IMPL with par- with the exception. The rule Parallel-Throw:
allel composition and synchronisation. The Hoare-Parallel Throw ∈ set cs
development shows how the OG method can be formalised Γ ` hParallel cs, si → hThrow , si
in Isabelle/HOL, introducing syntax and the small-step se-
mantics for parallel components. We largely reuse this ap- captures this behaviour, where set just converts a list to a set.
proach with two major deviations. Firstly, we do not incor- However, the parallel program may also continue its compu-
porate annotations into C OMPLX abstract syntax but rather tation, delaying the exception, provided by the fundamental
represent annotations using a separate datatype. Annotations Parallel rule:
and programs will be related in the next section by means of Γ ` hcsi , si → hc, s0 i i < |cs|
the OG logic. This way the abstract syntax remains simple
Γ ` hParallel cs, si → hParallel cs[i := c], s0 i
and clear, and we can reuse the existing C-to-Isabelle parser.
Secondly, we do not separate parallel and sequential pro- where |cs| denotes the length of the list cs, csi the i-th
grams into different layers, but rather have one datatype rep- (counting from 0) element of cs, and cs[i := c] the list cs
resenting both. These decisions make the soundness proof with its i-th element replaced by c. Furthermore, a paral-
more complicated, but allow C OMPLX programs to have lel program is allowed to terminate properly only if all its
nested parallelism, thus lifting unnecessary syntactic restric- threads do so. This is described by the Parallel-Skip rule:
tions.
In this sense, C OMPLX just extends the S IMPL abstract ∀c ∈ set cs. c = Skip
syntax by two new constructors: Parallel cs and Await b c: Γ ` hParallel cs, si → hSkip, si
141
amenable to automation. For sequential S IMPL programs, For instance, the following is a C OMPLX program with
S IMPL’s Hoare logic allows for weakest pre-condition style the annotations and program text combined.
reasoning, generating intermediate assertions, and a small
x := 0;; y := 0;;
set of verification conditions that guarantee partial correct- COBEGIN
ness (i.e. correctness in case of termination). For our con- {|a|} x := 1 {|Qx |}, {|Ax |} k {|b|} y := 1 {|Qy |}, {|Ay |}
current C OMPLX programs, we create an OG logic, similar COEND
to the one defined in Hoare-Parallel, that breaks down the
correctness of a parallel program into local correctness and This produces two different trees, one for the program
global correctness verification conditions. itself (where Basic f models state update by the function
f , here variable assignment):
4.1 Annotations
As explained in section 3, we use a single datatype to repre- Seq (Basic (x update (λ-. 0)))
sent sequential and concurrent programs. Moreover, our OG (Seq (Basic (y update (λ-. 0)))
annotations are specified using a separate datatype called an (Parallel [Basic (x update (λ-. 1)),
annotation tree, which is isomorphic to the abstract syntax Basic (y update (λ-. 1))]))
tree of the C OMPLX program. The annotation tree contains
assertions at each step in the program and is represented as and a separate annotation tree of the form
follows:
AnnComp (AnnExpr {|True|})
a= AnnExpr r | AnnRec r a | AnnWhile r r a
(AnnComp (AnnExpr {|True|})
| AnnComp a a | AnnCond r a a
(AnnPar [(AnnExpr {|a|}, {|Qx |}, {|Ax |}),
| AnnPar l | AnnCall r i
(AnnExpr {|b|}, {|Qy |}, {|Ay |})]))
Non-recursive command constructors such as Skip, Throw ,
etc. are annotated via an AnnExpr node, which carries a In the annotation tree, the trivial, unused assertions for
single assertion r that is merely a set of states and is also the sequential parts are automatically added by the syntactic
used for post-conditions of OG rules. AnnRec is used to sugar, removing the burden from the user.
annotate recursive commands, such as Await, DynCom or
Guard s, that hold another annotated command a. While- 4.2 Owicki-Gries Rules
commands require a special annotation type that provides We define an OG statement of the form
an assertion for the while, a loop invariant, as well as an
annotation tree for the loop body. Sequential composition Γ, Θ `/F a c {|Q|}, {|A|}
and Catch statements are annotated via AnnComp, where
stating that the C OMPLX program c with the annotation tree
an annotation sub-tree is provided for each component of the
a either ends in one of the fault states specified by F , or a
sub-commands. Similarly, AnnCond is used for conditional
Normal state. If that Normal state is an exception, it must
statements, but in addition to the two annotation sub-trees, it
satisfy the abrupt-condition A, otherwise it must satisfy the
carries an assertion for the conditional statement itself.
post-condition Q. Γ is the procedure environment, mapping
AnnPar is used to annotate Parallel statements, hence,
function names to function bodies, and Θ is the annotation
it stores a list l of triples containing an annotation tree, a
environment, mapping function names to annotation trees.
post-condition and an abrupt-condition, with one element
To enable weakest pre-condition reasoning when proving
in the list per parallel component. The post-conditions and
a sequential part of a program (i.e. within an Await or top-
abrupt-conditions must be specified by the user, because
level non-parallel commands), we have another OG state-
they are part of the interference freedom requirements. More
ment which takes an extra pre-condition {|P |}:
specifically, we must show that none of these conditions can
be violated due to other components activity. Γ, Θ `
`/F {|P|} a c {|Q|}, {|A|}
Finally, Call statements are annotated with AnnCall ,
which holds an assertion r and a routine index i of type This means that we duplicate every OG rules and the
natural number, specifying which annotation tree to select sequential version of a rule ignores the annotation tree. We
from the annotation environment. We return to this at the borrowed this idea from Hoare-Parallel, which also has two
end of subsection 4.2. versions for each rule. In our case, the annotation tree exists
Despite having a separate datatype for the program and but is only used as soon as we switch to parallel mode.
the annotation tree, C OMPLX’s syntactic sugar allows a user Figure 1 illustrates some of the important OG logic rules
to annotate a program directly. This way we specify asser- for C OMPLX. We omitted all the rules used for sequential
tions at each step of the program, making it easy to keep reasoning except for SeqParallel which allows switching
track of the assertions when following the control flow of from sequential mode (denoted by
) to parallel mode (de-
the program. noted by `). This rule would be used when the program is
142
P ⊆ pre (AnnPar as) Γ, Θ `/F (AnnPar as) (Parallel cs) {|Q|}, {|A|}
S EQ PARALLEL
Γ, Θ `
`/F P (AnnPar as) (Parallel cs) {|Q|}, {|A|}
|as| = |cs| ∀ i<|cs|. Γ, Θ `/F (pres as[i] ) cs[i] (postcond as[i] ), (abrcond as[i] )
\ [
interfree Γ Θ F as cs map postcond as ⊆ {|Q|} map abrcond as ⊆ {|A|}
PARALLEL
Γ, Θ `/F (AnnPar as) (Parallel cs) {|Q|}, {|A|}
Γ, Θ `
`/F (r ∩ b) P c {|Q|}, {|A|} atom-com c r ⊆ pre a ∀ s∈r. Γ, Θ `/F a (d s) {|Q|}, {|A|}
AWAIT DYN C OM
Γ, Θ `/F (AnnRec r P) (Await b c) {|Q|}, {|A|} Γ, Θ `/F (AnnRec r a) (DynCom d) {|Q|}, {|A|}
Γ, Θ `/F P c {|Q|}, {|A|} r ∩ g ⊆ pre P r ∩ − g 6= ∅ −→ f ∈ F
G UARD
Γ, Θ `/F (AnnRec r P) (Guard f g c) {|Q|}, {|A|}
Θ p = Some as r ⊆ pre as[n] Γ p = Some b n < |as| Γ, Θ `/F as[n] b {|Q|}, {|A|}
C ALL
Γ, Θ `/F (AnnCall r n) (Call p) {|Q|}, {|A|}
finished dealing with an initial sequential part and reaches elaborate on this in section 6. In order to be able to reason
a parallel composition. Note that the pre-condition {|P |} in about dynamic commands in OG, we must be able to anno-
the sequential OG statement disappears in the parallel one, tate them. Since program annotations are static, they must
as long as it implies the pre-condition of the assertion tree. not depend on the state of the program. Thus our framework
Also note that the OG rules ensure that the annotation tree restricts their use to dynamic commands that can be anno-
and the program match, e.g. a Parallel statement can only be tated statically. DynCom is derivable so long as an annota-
proved correct if provided with an AnnPar annotation. tion tree a can be provided and that it allows derivation of the
As explained in section 3, C OMPLX allows for nested command produced by the dynamic command d for any state
Parallel statements. Several conditions must be met when allowed by the assertion on DynCom. An additional require-
using the Parallel rule to derive a Parallel statement. Ev- ment for the annotation tree to be valid is that its first asser-
ery component of Parallel must itself be derivable. pres, tion must be allowed by the assertion on DynCom (i.e. r).
postcond and abrcond respectively return the annotation pre a returns the first assertion of the annotation tree a.
tree, the post-condition and the abrupt-condition of an el- The Guard rule is straightforward. For the command
ement of the list in AnnPar described earlier. While the Guard f g c, if the guard condition g is not satisfied, the fault
intersection of the post-conditions of all components must f must be allowed by the fault set F of the OG statement.
imply the post-condition of the overall Parallel , for abrupt- The rule asserts this by requiring that, when the fault is not
conditions only one of the components must satisfy the allowed by the OG statement, the assertion r allows more
abrupt-condition of the Parallel . This is explained by the states than the ones that do not satisfy the guard.
fact that exceptions can interrupt other components. The key The last interesting rule is Call . The annotation environ-
requirement for derivability of Parallel is interfree which ment Θ stores a list of annotation trees per function. Since
specifies interference freedom — we return to this definition a function can be called from multiple places and each call
in next section. may require a different set of assertions, multiple annotation
A derivation of Await b c requires a sequential derivation trees of the same function may be kept in the environment.
of c with the assertion r combined with the condition b as AnnCall provides a routine index to select which tree to use.
pre-condition. In addition, the command c must be deprived When deriving Call , the annotation environment needs to be
of Parallel and Call statements since they cannot be atomic correctly initialised such that the requested annotation tree
and thus are forbidden in Await. This restriction is achieved matches the function body. This way a derivable program
by the atom-com predicate and guarantees that a program cannot end in a Stuck state because of an undefined function
does not end in a Stuck state because of a non-atomic oper- call. Ideally, this index would be computed by the translation
ation found in an Await. from C to C OMPLX.
Dynamic commands are functions that produce a com-
mand from a state. They provide a general mechanism to 4.3 Interference Freedom
model programs that need to introspect their state. For in-
As explained in section 2, interference freedom states that,
stance, they could be used to model self-modifying code.
for every atomic command c extracted from parallel com-
However, for C verification their use is limited to restoring
ponents, all the commands it may be interleaved with have
the value of local variables when a function is called. We
their assertions preserved by the execution of c. C OMPLX’s
143
interfree definition follows the same principle as Hoare- obligations get easily discharged using Isabelle/HOL au-
Parallel’s, but with several important differences. tomation. This makes our framework ideal for concurrency
First, in order to support function calls we extract asser- verification as finding the right correctness assertions should
tions and atomics using relations instead of functions. Ex- be the bulk of the work for verifying a concurrent program.
tracting assertions and atomic commands from a program
requires going through every statement including statements 5. Soundness Proof
inside function bodies. To avoid divergence, the extraction Verification using logic rules and a VCG is much more effi-
functions must keep track of which functions have been pro- cient than reasoning directly with the semantics, but it needs
cessed. The resulting function must maintain a state and to be proven sound if we want to preserve the same level
becomes hard to use when induction is required. In addi- of trust. In this section we outline our proof that C OMPLX’s
tion, C OMPLX’s separation between program and annota- OG rules presented in section 4 are sound with respect to
tions makes it harder to extract assertions and atomics using the semantics presented in section 3. Namely we prove, in
a function. Since the annotation tree and the program struc- Isabelle/HOL, the following theorem (identical to S IMPL’s
ture are not synchronised by construction, a function would soundness theorem):
have to be partial or undefined if the annotation tree does not Γ, Θ `/F a c {|Q|}, {|A|} =⇒ Γ |=/F (pre a) c {|Q|}, {|A|}
match the structure of the program. To address these issues,
This states that any Hoare triple3 that is derivable from the
in C OMPLX we use relations instead of functions to extract OG-rules is valid, where validity is defined in terms of the
assertions and atomics. Using a relation, any mismatch be- small-step semantics (below e.g. Normal ‘ {|P |} denotes the
tween annotation tree and program structure simply results image of {|P |} under Normal , embedding this {|P |} into
in the relation not holding, and the infinite-recursion prob- extended states):
lem goes away since the relation does not have to terminate. Γ |=/F {|P|} c {|Q|}, {|A|} ≡
More importantly, by using a relation we can describe an in-
∀ s t c 0.
finite set of assertions/atomics, which is specifically required Γ ` (c, s) →∗ (c 0, t) −→
for DynCom. final (c 0, t) −→
Second, C OMPLX’s semantics is significantly more com- s ∈ Normal ‘ {|P|} −→
plicated than Hoare-Parallel’s. In particular, as the C OMPLX t∈/ Fault ‘ F −→
semantics executes the program, it reduces the program to a c 0 = Skip ∧ t ∈ Normal ‘ {|Q|} ∨ c 0 = Throw ∧ t ∈ Normal ‘ {|A|}
final command (i.e. Skip or Throw ) which denotes termina-
That is, a program c is called valid if final states of any of
tion of execution. This is visible on most of the small-step se-
its full executions without any faults from a state s satisfying
mantics rules presented in section 3, such as Parallel-Throw,
P , satisfy the relevant post-condition. More precisely, if c
Parallel-Skip... Consequently, Skip and Throw commands
executes, after multiple steps, into either Skip or Throw
have two purposes: they denote final configurations, and they
(denoted by final ) then the final state t satisfies Q if c0 is
also are legitimate commands that can be found in any given
Skip and A if c0 is Throw . Note that a sequence of small-
program. In the latter case, they must be annotated manu-
steps cannot reach both, Skip and Throw . It is also worth
ally. However, in the former case the C OMPLX framework
noting, that as a consequence of separating annotations from
must automatically generate assertions for them. Typically,
programs, the notion of validity is purely semantical, thus
the assertion on a Skip will be the assertion of the next com-
completely independent from annotations which are only
mand, or, if it is the last command of the program, the post-
needed for derivability.
condition. Hence, the relation that extracts assertions takes
We now outline the main challenges in the soundness
the post-condition and the abrupt-condition of the program
proof that proceeds by induction on the structure of the OG-
and generates the appropriate assertions for every semantics
rules. For the sake of brevity, in the following we will focus
rule that leads to a final configuration.
on the cases when all considered states are Normal : apart
Finally, since C OMPLX allows nested Parallel state-
from these we get several corner cases, such as that guards
ments, assertions need to be collected recursively on each
can fail only within specified Fault states or absence of un-
of the parallel components.
defined function calls. These are, however, of technical na-
4.4 VCG ture and do not contribute much to the structure and com-
In order to automate the creation of verification conditions plexity of the overall proof.
for programs in C OMPLX, we ported and extended Hoare- All OG-rules, beside those for parallel composition and
Parallel’s VCG. We added support for several constructors, synchronisation, retain their S IMPL form, such that in these
including Catch, Call , Guard and DynCom. This involved cases we proceed similarly to the sequential setting. This
writing Isabelle/HOL tactic rules to decompose the deriva- changes, of course, as soon as we reach the parallel com-
tion of these commands and convert interference freedom position and await cases.
goals to OG statements showing that assertions are pre- 3 Technically, this is more a Hoare quadruple but we still use the more
served. As in Hoare-Parallel, most of the generated proof traditional term of triple.
144
The major challenges arise in the proof of the paral- 6. Case Study
lel case, i.e. when c = Parallel cs. We can assume all the We used our C OMPLX framework to reproduce the proof
premises of the OG-rule PARALLEL (see Figure 1), in partic- of correctness of a few examples of concurrent algorithms
ular that interference freedom holds for the parallel compo- that had been verified within Hoare-Parallel, including the
nents cs with respect to the annotation. Moreover, we can as- proof of Peterson’s solution to the mutual exclusion prob-
sume Γ ` hParallel cs, Normal xi →∗ hc0 , Normal yi with lem [Prensa Nieto 2002]. Our proofs can be found on-
x satisfying the annotated pre-condition and c0 being Skip line [COMPLX] and were very easily achieved once our
or Throw . What we need to prove is that y satisfies the rele- framework was complete. This shows that C OMPLX is ro-
vant post-condition. For this we induct on the closure of the bust and backward compatible with Hoare-Parallel, as none
small-step relation, and the challenge is to show that all the of the proofs required extra work. The VCG generates ap-
assumed conditions (from the premise of the OG rule, e.g. proximately the same number of proof obligations and dis-
interference freedom) are preserved by each execution step charging them takes a similar processing time. These exam-
(to be able to apply the induction hypothesis). This is a chal- ples, however, did not exercise any C-specific features.
lenge because each step ‘consumes’ a part of the program, To demonstrate the practicality of our framework in veri-
which needs to be reflected in the annotation tree. We cap- fying concurrent C code, we created an example (also avail-
ture this by a separate lemma, where we collect all the neces- able online [COMPLX]) of a concurrent C program that ex-
sary properties relating pre- and post-configurations of any ercises the specific features that C OMPLX supports. In par-
small-step. That is, if Γ ` hc, Normal xi → hc0 , Normal yi ticular, our example uses exceptions, guards and function
holds for any c, x, c0 , y, and the program c is derivable with calls, all of which are not supported by Hoare-Parallel.
an annotation structure a by the OG-rules such that s satis- In our example, we extracted manually the program
fies the annotated pre-condition, then we can find an anno- model from the C source code. The C program and the C OM -
tation structure a0 such that c0 is derivable with a0 , y satis- PLX program are both less than 20 lines, and the whole
fies the pre-condition in a0 and, moreover, any assertion or model is ≈230 lines of Isabelle/HOL definitions, includ-
atomic of a0 is an assertion or atomic of a, respectively. Since ing the complete set of assertions used to annotate the pro-
the program c is an arbitrary C OMPLX program, we induct gram and verify its correctness. The VCG generates 688
on the structure of c. Here again, only the await and paral- conditions and most of them are easily discharged using Is-
lel cases are more involved. For await we can rely on the abelle/HOL automation. Once again, the bulk of the work
canonical restriction that the body of any Await-construct lies in finding the right correctness assertions.
is purely sequential, i.e. a S IMPL program in fact. In the The aim of the program is to compute the combined sum
parallel case, however, we have to deploy our interference of all the elements of multiple arrays. It does this by running
freedom assumption to show that any post-state of the whole a number of threads in parallel, each computing the sum of
parallel construct will satisfy annotated conditions regard- elements of one of the arrays, and then adding the result to
less of which of the constituting components does its small a global variable gsum shared by all threads. We restrict
step. To this end we need to establish a connection between the example to two arrays and threads, but this could be
the small-step semantics and atomics as follows. Any pro- generalised: we would then just need to generate accordingly
gram transition Γ ` hc, Normal xi → hc0 , Normal yi, where more copies of the function sumarr , pairwise disjoint in
Normal x satisfies the annotated pre-condition and x 6= y, local variables, such that each thread can invoke its own copy
can only happen due to an atomic subcomponent cc of c that of sumarr . The correctness statement for this program is:
performs the step Γ ` hcc, Normal xi → hSkip, Normal yi.
Now, the interference freedom property states that each of Γ, Θ |`
`/F {|precond|}
such atomic steps preserves assertions of any component COBEGIN
other than the one that performs the step. This gives us the SCHEME [0 ≤ m < 2]
call-sumarr m
preservation we need to carry assumptions over single steps
{|local-postcond m|}, {|False|}
of execution. COEND
For the proof of the top-level Await case we similarly {|postcond|}, {|False|}
can assume Γ ` hAwait b cc, Normal xi →∗ hc0 , Normal yi
with x satisfying the annotated pre-condition, c0 being Skip The SCHEME syntax models a parametric number of par-
or Throw , and Await b cc being derivable by the OG-rules. allel programs. Here we use it to model the creation of
Moreover, by induction hypothesis we also know that the two threads running concurrently, each calling the func-
await-body cc is valid. On the other hand, from the se- tion sumarr . The post-condition (definition not shown)
mantics of Await we can conclude that y can only be ob- states that the global variable gsum is indeed equal to
tained by a certain number of small-step transformations the combined sum of all elements of all arrays. Since the
of hcc, Normal xi until a Skip or Throw configuration is function sumarr cannot terminate with an exception, the
reached, establishing the desired result. abrupt-condition is false, which forces us to prove that all
exceptions are caught. As explained in section 4, prov-
145
ing interference freedom also requires that we specify the
post-condition (local-postcond) and abrupt-condition (false call-sumarr m ≡
{|local-precond m|} CALLX (sumarr-init m)
again) of the parallel component.
{|sumarr-precond m|} ( 00sumarr 00, m) m
To begin we explain the state of the program, then how we (sumarr-restore m) (λ- -. Skip)
model function calls, and finally how the sumarr function is {|sumarr-restore-post m|} {|sumarr-return-post m|}
defined. {|False|} {|False|}
State The state of the program is modelled with the
following record: Figure 2: Annotations for the function sumarr .
146
parametrise sumarr with m, which is used as a routine in-
sumarr-init m ≡ dex to select which local variables to use.
λs. s(|tarr := (tarr s)(m := (garr s)[m] ), The first two lines initialise the local variables tsum and
tid := (tid s)(m := m + 1), ti := (ti s)(m := undefined), ti to zero. Note that a for-loop is trivially converted to a
tsum := (tsum s)(m := undefined)|) while-loop by moving the loop counter update to the end
of the loop body. The while-loop is wrapped inside a try-
catch statement because C OMPLX, just like S IMPL, uses
sumarr-restore m ≡ exceptions to model early exit of a loop. Hence, the break
λs t. t(|tarr := (tarr t)(m := tarr s m), tid := (tid t)(m := tid s m), statement present in the C code is replaced with a Throw in
ti := (ti t)(m := ti s m), tsum := (tsum t)(m := tsum s m)|) C OMPLX, and the CATCH block only contains a Skip, i.e.
To reason about function calls in OG, the user also has do nothing. This means that when the exception is thrown, it
to provide assertions for every step in the control flow of has the effect of breaking out of the loop.
callx . To facilitate this, there is an equivalent helper function One of the most important aspects of verifying C code
ann callx . The arguments of the CALLX statement are is proving the absence of behaviours undefined by the C
then the commands for dealing with argument passing and standard. In both S IMPL and C OMPLX undefined behaviours
scoping, the corresponding annotations, and the function are usually specified using guards. For instance, in our case
name and index used when looking up the procedure and there could be undefined behaviour if an invalid pointer is
annotation environment. dereferenced. Therefore, every time a pointer is accessed it
One restriction of our current implementation of CALLX must be protected by a guard forcing us to prove that the
is that both initialising and restoring local variables is per- pointer is indeed valid.
formed in one step. This does not match the reality of C, In Figure 4b, since tarr is a pointer, every access is
which uses multiple instructions and can potentially be in- guarded with an array-in-bound check which guarantees
terleaved. We believe that it would be relatively straightfor- that tarr is a valid pointer and that the index ti is less
ward to change our framework to use multiple steps, one for than the length of the array. If the guard is not satisfied the
each local variable. Additionally, we should be able to create program returns the fault InvalidMem indicating an invalid
syntactic sugar that hides many of these details from the end memory access. Having explicit guard commands in C OM -
user. PLX also allows us to reason about concurrent programs that
In Figure 2, local-precond corresponds to the first asser- can actually end in a specific Fault state. For instance, we
tion of the parallel component, whereas summar-precond is are able to prove that in some circumstances a program is
the assertion once the arguments and local variables have guaranteed to result in a Fault state.
been initialised. The other assertions describe the state be- After the loop, the model calls the function lock , to ac-
fore restoring local variables (summar-restore) and before quire the global mutex that protects the shared variables
extracting the return value from the state (summar-return), gsum and gdone. Since lock and unlock only access a
for normal termination of the function. For abrupt termina- global variable (the mutex) and do not take any arguments,
tion these assertions are false, as the function sumarr cannot their call does not require saving and restoring of local vari-
terminate with an exception. ables. The definition of lock and unlock follows:
lock m ≡ {|...|} AWAIT glock = 0 THEN glock := 1 END
The sumarr function Returning to our case study, Fig-
ure 4a shows the body of the sumarr function, as it would unlock m ≡ {|...|} glock := 0
be implemented in C. The pointer tarr refers to the array of
The mutex is modelled by using glock , a global variable
unsigned integers that is being summed and tid is a thread
set to 1 when the lock is held and 0 otherwise. The semantics
identifier of value 1 or 2 depending on the thread.
of Await guarantees that only one thread can be inside the
The loop calculates the sum of each element of the ar-
lock at a time.
ray and at each iteration if the sum or the current element
exceeds MAXSUM, we break out of the loop and cap tsum Summary C OMPLX was designed to reason about an ac-
at MAXSUM. This prevents potential word overflows, as- curate representation of the C code, without requiring that
suming that NSUM and MAXSUM are chosen appropriately. programmers radically change their programming style and
After the loop, we invoke the lock and unlock functions to habits. A key feature of C OMPLX is the syntactic sugar
protect the global variables gsum and gdone. In the C code, which allows annotating programs directly on the program
lock and unlock are implemented using a mutex. model, despite having a separate datatype for annotation tree
Figure 4b shows the C OMPLX model in Isabelle/HOL of and program. This gives us the best of both worlds: a user-
this function. As seen in subsection 4.1, C OMPLX’s syntac- friendly framework for annotating program and a neat lan-
tic sugar allows the program to be directly annotated. Addi- guage abstract syntax which is not cluttered with irrelevant
tionally, concurrent executions of functions require different annotations. The lack of exceptions in Hoare-Parallel would
instances of any local variables. Therefore, in Figure 4b we force reimplementing our code to avoid having a break
147
sumarr m ≡
{|...|} tsum := tsum(m := 0);;
void sumarr ( unsigned i n t ∗ t a r r , {|...|} ti := ti(m := 0);;
unsigned i n t t i d )
{
TRY {|...|} WHILE ti m < NSUM INV {|...|}
unsigned i n t t i ; DO {|...|} (InvalidMem, {|array-in-bound (tarr m) (ti m)|}) 7−→
u n s i g n e d i n t tsum ; {|...|} tsum := tsum(m := tsum m + array-nth (tarr m) (ti m));;
{|...|} (InvalidMem, {|array-in-bound (tarr m) (ti m)|}) 7−→
tsum = 0 ; {|...|} IF MAXSUM ≤ tsum m ∨ MAXSUM ≤ array-nth (tarr m) (ti m)
f o r ( t i = 0 ; t i < NSUM; t i ++) { THEN {|...|} tsum := tsum(m := MAXSUM);;
tsum += t a r r [ t i ] ;
{|...|} THROW
i f ( tsum >= MAXSUM | |
t a r r [ t i ] >= MAXSUM) { ELSE {|...|} SKIP
tsum = MAXSUM; FI;;
break ; {|...|} ti := ti(m := ti m + 1)
} OD
} CATCH {|...|} SKIP END;;
lock ( ) ;
{|...|} SCALL ( 00lock 00, 0) m;;
gsum += tsum ;
gdone | = t i d ; {|...|} gsum := gsum + tsum m;;
unlock ( ) ; {|...|} gdone := (gdone OR tid m);;
} {|...|} SCALL ( 00unlock 00, 0) m
(a) C code
(b) C OMPLX model
Figure 4: The C code and matching C OMPLX model of our case study
statement in the middle of the loop. Furthermore, support the simple high-level language IMP) and we introduced a
for guard statements is critical to enable C verification, be- technique that we called await-painting, essentially painting
cause they ensure that the semantics of the code is defined. our program with Await statements to limit the concurrency
Finally, supporting function calls is a key requirement for to places where it actually occurs. This technique allowed us
our framework, which we intend to use on larger scale veri- to proof-engineer an Isabelle/HOL tactic that automatically
fication projects. discharges most of the verification conditions generated by
OG. We successfully used the tactic to verify an abstract
7. Related Work model of the eChronos OS scheduling behaviour. C OMPLX
will enable us to extend this verification to the C implemen-
Logics for Concurrency Over the years, many logics were
tation.
developed for reasoning about concurrency, the oldest and
In C OMPLX, just like S IMPL, the notion of state is ab-
most straightforward of which is OG. OG provides, however,
stract: we propose a generic language for reasoning about
no modular way to reason about memory and quickly leads
concurrent imperative code. Modelling memory is orthogo-
to an explosion in the number of verification conditions
nal to the work done in this paper. The C-to-Isabelle parser
that need to be proven. Rely-Guarantee (RG) [Jones 1983],
defines a concrete notion of state on top of S IMPL which, for
Concurrent Separation Logic (CSL) [OHearn 2007], and a
instance, can be reasoned about using separation logic [Tuch
number of more recent combinations and extensions of these
et al. 2007]. Building a framework in the spirit of FCSL
(e.g. [Vafeiadis 2008; da Rocha Pinto et al. 2014]) have been
(fine-grained concurrent separation logic) [Nanevski et al.
developed since to overcome the modularity issues of OG.
2014; Sergey et al. 2015] on top of the C OMPLX language
The separation-based logics typically rely on ownership over
would be interesting future work.
shared state: threads need to lock their accesses to shared
Recent work showed that, as is, OG is unsound for weak
state and ownership can be transferred along acquire/release
memory models but can be extended in a sound logic by
atomic memory accesses.
strengthening its interference-freedom condition [Lahav and
In recent work [Andronick et al. 2015, 2016], we found
Vafeiadis 2015]. We could look at a similar approach if we
that using the simple OG method is suitable for our reason-
want to support weak memory models in the future.
ing of interrupt-induced concurrency in racy OS code. In that
code, the OS API functions, the scheduler and the interrupt Tools for Verification of Concurrent C We focus here
handlers all concurrently modify shared variables without on tools that allow the verification of specific properties
any synchronisation (in order to meet stringent low-latency or specifications, rather than e.g. static analysers that can
requirements). The correctness argument needs to rely on only detect specific classes of errors. VCC [Cohen et al.
fine-grain assertions at these sharing points; it cannot rely 2009] is an industrial-strength verification environment for
on some atomicity or ownership argument. We used OG (at low-level concurrent system code. It is an assertional, auto-
148
matic, deductive code verifier for C, where specifications in to verify concurrent operating systems, such as the inter-
the form of function contracts, data invariants, and loop in- ruptible eChronos embedded operating system or multicore
variants are added to the C code to guide VCC. From the seL4.
annotated program, VCC generates verification conditions,
which it then tries to discharge using the automatic theo- Acknowledgments
rem prover Z3 [de Moura and Bjørner 2008] or through the
This research is supported by the Air Force Office of Scientific
Boogie verifier [Barnett et al. 2006]. VCC has been used,
Research, Asian Office of Aerospace Research and Development
among others, to verify the Microsoft Hyper-V hypervisor
(AOARD) and U.S. Army International Technology Center - Pa-
and has also been used in the Verisoft XT project [Verisoft
cific under grant FA2386-15-1-4055.
XT]. Moreover, Isabelle/HOL was used as a backend to
VCC for the verification of certifying graph algorithms from
LEDA [Alkassar et al. 2014]. When the C-to-Isabelle parser References
was open-sourced, the LEDA verification project switched E. Alkassar, S. Böhme, K. Mehlhorn, and C. Rizkallah. A frame-
to only using S IMPL and the C-to-Isabelle parser and redid work for the verification of certifying computations. Journal of
their verification completely within Isabelle/HOL, in order Automated Reasoning, 52(3):241–273, 2014. ISSN 0168-7433.
to provide higher trust guarantees [Noschinski et al. 2014; doi: 10.1007/s10817-013-9289-2.
Rizkallah 2015]. Unlike an LCF based theorem prover (e.g. S. Amani, A. Hixon, Z. Chen, C. Rizkallah, P. Chubb, L. O’Connor,
Isabelle/HOL or Coq [Bertot and Castéran 2004]), VCC re- J. Beeren, Y. Nagashima, J. Lim, T. Sewell, J. Tuong, G. Keller,
lies on a large trusted computing base that includes the en- T. Murray, G. Klein, and G. Heiser. Cogent: Verifying high-
assurance file system implementations. In ASPLOS, Atlanta,
tire VCC engine and Z3 [Noschinski et al. 2014; Rizkallah
GA, USA, Apr 2016. doi: 10.1145/2872362.2872404.
2015]. Similar to VCC, VeriFast [Jacobs et al. 2010] relies
on Z3. We would like to enable reasoning about concurrency, J. Andronick, C. Lewis, and C. Morgan. Controlled Owicki-Gries
within an LCF based theorem prover in order not to compro- concurrency: Reasoning about the preemptible eChronos em-
bedded operating system. In Workshop on Models for Formal
mise on trust.
Analysis of Real Systems (MARS), 2015.
A number of recent efforts provide tools to reason about
concurrency in Coq. Most of these efforts are based on J. Andronick, C. Lewis, D. Matichuk, C. Morgan, and C. Rizkallah.
Proof of OS scheduling behavior in the presence of interrupt-
CSL and primarily focus on modular reasoning about non-
induced concurrency. In International Conference on Interactive
racy shared memory. The Verified Software Toolchain [Ap- Theorem Proving, Nancy, France, aug 2016.
pel 2012] provides machine-checked guarantees that the
A. W. Appel. Verified software toolchain. In A. Goodloe and
CSL assertions about concurrent C code with primitive lock
S. Person, editors, NASA Formal Methods - 4th International
operations hold down to the machine-language program.
Symposium, NFM 2012, Norfolk, VA, USA, April 3-5, 2012. Pro-
Iris [Jung et al. 2015, 2016] is a general and expressive logic ceedings, volume 7226 of Lecture Notes in Computer Science,
with a simple set of verified primitive mechanisms and proof page 2. Springer, 2012.
rules for modular reasoning about shared memory. Once
M. Barnett, B.-Y. E. Chang, R. DeLine, B. Jacobs, and K. R. M.
again, we are targeting potentially-racy high-performance Leino. Boogie: a modular reusable verifier for object-oriented
code for which OG fine-grain assertions are well-suited. programs. In 4th FMCO, volume 4111 of LNCS, pages 364–
387, Amsterdam, The Netherlands, 2006. Springer.
8. Conclusion and Future Work Y. Bertot and P. Castéran. Interactive Theorem Proving and Pro-
gram Development. Coq’Art: The Calculus of Inductive Con-
In this paper we have presented our C OMPLX framework
structions. Texts in Theoretical Computer Science. An EATCS
for sound verification of concurrent imperative code in Is- Series. Springer, 2004. ISBN 3-540-20854-2. doi: 10.1007/
abelle/HOL. We have emphasised how we use the Owicki- 978-3-662-07964-5.
Gries method in order to extend the S IMPL tool to cope
E. Cohen, M. Dahlweid, M. Hillebrand, D. Leinenbach, M. Moskal,
with concurrency. This way our framework inherits support T. Santen, W. Schulte, and S. Tobies. VCC: A practical system
for function calls and exception handling from S IMPL. The for verifying concurrent C. In S. Berghofer, T. Nipkow, C. Ur-
presented case-study illustrates how these features can be ban, and M. Wenzel, editors, 22nd TPHOLs, volume 5674 of
utilised in practical verification. LNCS, pages 23–42, Munich, Germany, 2009. Springer. doi:
Future work includes more proof engineering to increase 10.1007/978-3-642-03359-9 2.
ease of use, integration with the C-to-Isabelle parser, and COMPLX. cf. http://ts.data61.csiro.au/projects/
definition of more concrete notions of states. concurrency/complx.
With the work presented here, we bridge the gap between P. da Rocha Pinto, T. Dinsdale-Young, and P. Gardner. TaDA: A
the verification of abstract algorithms and that of their imper- logic for time and data abstraction. volume 8586 of LNCS, pages
ative implementations. We plan to extend the C-to-Isabelle 207–231. Springer, 2014. doi: 10.1007/978-3-662-44202-9 9.
parser to translate C code into C OMPLX code to provide URL http://dx.doi.org/10.1007/978-3-662-44202-9_
guarantees for concurrent low-level C code, with the aim 9.
149
L. M. de Moura and N. Bjørner. Z3: An efficient SMT solver. T. Nipkow, L. Paulson, and M. Wenzel. Isabelle/HOL — A
In TACAS, volume 4963 of LNCS, pages 337–340, Budapest, Proof Assistant for Higher-Order Logic, volume 2283 of LNCS.
Hungary, Mar 2008. Springer. ISBN 978-3-540-78799-0. doi: Springer, 2002. ISBN 978-3-540-43376-7. doi: 10.1007/
10.1007/978-3-540-78800-3 24. 3-540-45949-9.
B. Jacobs, J. Smans, and F. Piessens. A quick tour of the verifast L. Noschinski, C. Rizkallah, and K. Mehlhorn. Verification of cer-
program verifier. In Programming Languages and Systems - 8th tifying computations through AutoCorres and Simpl. In J. M.
Asian Symposium, APLAS 2010, Shanghai, China, November 28 Badger and K. Y. Rozier, editors, NASA Formal Methods, vol-
- December 1, 2010. Proceedings, pages 304–311, 2010. ume 8430 of LNCS, pages 46–61. Springer, 2014.
C. B. Jones. Tentative steps towards a development method for P. W. OHearn. Resources, concurrency, and local reasoning. Theor.
interfering programs. Trans. Progr. Lang. & Syst., 5(4):596–619, Comput. Sci., 375(1-3):271–307, Apr 2007. ISSN 0304-3975.
1983. doi: 10.1016/j.tcs.2006.12.035.
R. Jung, D. Swasey, F. Sieczkowski, K. Svendsen, A. Turon, S. Owicki and D. Gries. An axiomatic proof technique for parallel
L. Birkedal, and D. Dreyer. Iris: Monoids and invariants as an programs. Acta Informatica, 6:319–340, 1976.
orthogonal basis for concurrent reasoning. In S. K. Rajamani
L. Prensa Nieto. Verification of parallel programs with the Owicki-
and D. Walker, editors, Proceedings of the 42nd Annual ACM
Gries and rely-guarantee methods in Isabelle/HOL. PhD thesis,
SIGPLAN-SIGACT Symposium on Principles of Programming
Languages, POPL 2015, Mumbai, India, January 15-17, 2015, T.U. München, 2002.
pages 637–650. ACM, 2015. C. Rizkallah. A Simpl shortest path checker verification. In
R. Jung, R. Krebbers, L. Birkedal, and D. Dreyer. Higher-order Proceedings of Isabelle Workshop 2014, 2014.
ghost state. In J. Garrigue, G. Keller, and E. Sumii, editors, Pro-
C. Rizkallah. Verification of program computations. PhD the-
ceedings of the 21st ACM SIGPLAN International Conference
sis, Saarland University, 2015. URL http://scidok.sulb.
on Functional Programming, ICFP 2016, Nara, Japan, Septem-
uni-saarland.de/volltexte/2015/6254/.
ber 18-22, 2016, pages 256–269. ACM, 2016.
N. Schirmer. Verification of Sequential Imperative Programs in
G. Klein, J. Andronick, K. Elphinstone, G. Heiser, D. Cock, P. Der-
Isabelle/HOL. PhD thesis, Technische Universität München,
rin, D. Elkaduwe, K. Engelhardt, R. Kolanski, M. Norrish,
2006.
T. Sewell, H. Tuch, and S. Winwood. seL4: Formal verifica-
tion of an operating-system kernel. CACM, 53(6):107–115, Jun N. Schirmer. A sequential imperative programming language
2010. doi: 10.1145/1743546.1743574. syntax, semantics, hoare logics and verification environment.
Archive of Formal Proofs, Feb 2008. ISSN 2150-914x. http://
O. Lahav and V. Vafeiadis. Owicki-Gries Reasoning for Weak
isa-afp.org/entries/Simpl.shtml, Formal proof devel-
Memory Models, pages 311–323. Springer Berlin Heidelberg,
opment.
Berlin, Heidelberg, 2015.
I. Sergey, A. Nanevski, and A. Banerjee. Mechanized verification
K. Mehlhorn and S. Näher. The LEDA Platform for Combinatorial
of fine-grained concurrent programs. In ACM SIGPLAN Notices,
and Geometric Computing. Cambridge University Press, 1999.
volume 50, pages 77–87. ACM, 2015.
T. Murray, D. Matichuk, M. Brassil, P. Gammie, and G. Klein. Non-
interference for operating system kernels. In Chris Hawblitzel H. Tuch, G. Klein, and M. Norrish. Types, bytes, and separation
and Dale Miller, editor, CPP, pages 126–142, Kyoto, Dec 2012. logic. In Martin Hofmann and Matthias Felleisen, editor, POPL,
Springer. ISBN 978-3-642-35307-9. pages 97–108, Nice, France, Jan 2007. ACM. ISBN 1-59593-
575-4.
A. Nanevski, R. Ley-Wild, I. Sergey, and G. A. Delbianco. Com-
municating state transition systems for fine-grained concurrent V. Vafeiadis. Modular fine-grained concurrency verification. PhD
resources. In European Symposium on Programming Languages thesis, University of Cambridge, Computer Laboratory, jul 2008.
and Systems, pages 290–310. Springer, 2014. Verisoft XT. Verisoft XT. http://www.verisoftxt.de, 2010.
150