-
Practical Rely/Guarantee Verification of an Efficient Lock for seL4 on Multicore Architectures
Authors:
Robert J. Colvin,
Ian J. Hayes,
Scott Heiner,
Peter Höfner,
Larissa Meinicke,
Roger C. Su
Abstract:
Developers of low-level systems code providing core functionality for operating systems and kernels must address hardware-level features of modern multicore architectures. A particular feature is pipelined "out-of-order execution" of the code as written, the effects of which are typically summarised as a "weak memory model" - a term which includes further complicating factors that may be introduce…
▽ More
Developers of low-level systems code providing core functionality for operating systems and kernels must address hardware-level features of modern multicore architectures. A particular feature is pipelined "out-of-order execution" of the code as written, the effects of which are typically summarised as a "weak memory model" - a term which includes further complicating factors that may be introduced by compiler optimisations. In many cases, the nondeterminism inherent in weak memory models can be expressed as micro-parallelism, i.e., parallelism within threads and not just between them. Fortunately Jones' rely/guarantee reasoning provides a compositional method for shared-variable concurrency, whether that be in terms of communication between top-level threads or micro-parallelism within threads. In this paper we provide an in-depth verification of the lock algorithm used in the seL4 microkernel, using rely/guarantee to handle both interthread communication as well as micro-parallelism introduced by weak memory models.
△ Less
Submitted 30 July, 2024;
originally announced July 2024.
-
Separation of concerning things: a simpler basis for defining and programming with the C/C++ memory model (extended version)
Authors:
Robert J. Colvin
Abstract:
The C/C++ memory model provides an interface and execution model for programmers of concurrent (shared-variable) code. It provides a range of mechanisms that abstract from underlying hardware memory models -- that govern how multicore architectures handle concurrent accesses to main memory -- as well as abstracting from compiler transformations. The C standard describes the memory model in terms o…
▽ More
The C/C++ memory model provides an interface and execution model for programmers of concurrent (shared-variable) code. It provides a range of mechanisms that abstract from underlying hardware memory models -- that govern how multicore architectures handle concurrent accesses to main memory -- as well as abstracting from compiler transformations. The C standard describes the memory model in terms of cross-thread relationships between events, and has been influenced by several research works that are similarly based. In this paper we provide a thread-local definition of the fundamental principles of the C memory model, which, for concise concurrent code, serves as a basis for relatively straightforward reasoning about the effects of the C ordering mechanisms. We argue that this definition is more practical from a programming perspective and is amenable to analysis by already established techniques for concurrent code. The key aspect is that the memory model definition is separate to other considerations of a rich programming language such as C, in particular, expression evaluation and optimisations, though we show how to reason about those considerations in the presence of C concurrency. A major simplification of our framework compared to the description in the C standard and related work in the literature is separating out considerations around the "lack of multicopy atomicity", a concept that is in any case irrelevant to developers of code for x86, Arm, RISC-V or SPARC architectures. We show how the framework is convenient for reasoning about well-structured code, and for formally addressing unintuitive behaviours such as "out-of-thin-air" writes.
△ Less
Submitted 6 April, 2022;
originally announced April 2022.
-
Parallelized sequential composition, pipelines, and hardware weak memory models
Authors:
Robert J. Colvin
Abstract:
Since the introduction of the CDC 6600 in 1965 and its `scoreboarding' technique processors have not (necessarily) executed instructions in program order. Programmers of high-level code may sequence independent instructions in arbitrary order, and it is a matter of significant programming abstraction and computational efficiency that the processor can be relied upon to make sensible parallelizatio…
▽ More
Since the introduction of the CDC 6600 in 1965 and its `scoreboarding' technique processors have not (necessarily) executed instructions in program order. Programmers of high-level code may sequence independent instructions in arbitrary order, and it is a matter of significant programming abstraction and computational efficiency that the processor can be relied upon to make sensible parallelizations/reorderings of low-level instructions to take advantage of, eg., multiple ALUs. At the architectural level such reordering is typically implemented via a per-processor pipeline, into which instructions are fetched in order, but possibly committed out of order depending on local considerations, provided any reordering preserves sequential semantics from that processor's perspective. However multicore architectures, where several pipelines run in parallel, can expose these processor-level reorderings as unexpected, or `weak', behaviours. Such weak behaviours are hard to reason about, and (via speculative execution) underlie at least one class of widespread security vulnerability.
In this paper we introduce a novel program operator, \emph{parallelized sequential composition}, which can be instantiated with a function that controls the reordering of atomic instructions. It generalises both sequential and parallel composition, and when appropriately instantiated exhibits many of the weak behaviours of well-known hardware weak memory models. Our framework admits the application of established compositional techniques (eg. Owicki-Gries) for reasoning about weak behaviours, and is convenient for abstractly expressing properties from the literature. The semantics and theory is encoded and verified in a theorem prover, and we give an implementation of the pipeline semantics which we use to empirically show conformance against established models of ARM and RISC-V.
△ Less
Submitted 6 May, 2021;
originally announced May 2021.
-
An abstract semantics of speculative execution for reasoning about security vulnerabilities
Authors:
Robert J. Colvin,
Kirsten Winter
Abstract:
Reasoning about correctness and security of software is increasingly difficult due to the complexity of modern microarchitectural features such as out-of-order execution. A class of security vulnerabilities termed Spectre that exploits side effects of speculative, out-of-order execution was announced in 2018 and has since drawn much attention. In this paper we formalise speculative execution and i…
▽ More
Reasoning about correctness and security of software is increasingly difficult due to the complexity of modern microarchitectural features such as out-of-order execution. A class of security vulnerabilities termed Spectre that exploits side effects of speculative, out-of-order execution was announced in 2018 and has since drawn much attention. In this paper we formalise speculative execution and its side effects with the intention of allowing speculation to be reasoned about abstractly at the program level, limiting the exposure to processor-specific or low-level semantics. To this end we encode and expose speculative execution explicitly in the programming language, rather than solely in the operational semantics; as a result the effects of speculative execution are captured by redefining the meaning of a conditional statement, and introducing novel language constructs that model transient execution of an alternative branch. We add an abstract cache to the global state of the system, and derive some general refinement rules that expose cache side effects due to speculative loads. Underlying this extension is a semantic model that is based on instruction-level parallelism. The rules are encoded in a simulation tool, which we use to analyse an abstract specification of a Spectre attack and vulnerable code fragments.
△ Less
Submitted 9 March, 2020;
originally announced April 2020.
-
A high-level operational semantics for hardware weak memory models
Authors:
Robert J. Colvin,
Graeme Smith
Abstract:
Modern processors deploy a variety of weak memory models, which for efficiency reasons may execute instructions in an order different to that specified by the program text. The consequences of instruction reordering can be complex and subtle, and can impact on ensuring correctness. In this paper we build on extensive work elucidating the semantics of assembler-level languages on hardware architect…
▽ More
Modern processors deploy a variety of weak memory models, which for efficiency reasons may execute instructions in an order different to that specified by the program text. The consequences of instruction reordering can be complex and subtle, and can impact on ensuring correctness. In this paper we build on extensive work elucidating the semantics of assembler-level languages on hardware architectures with weak memory models (specifically TSO, ARM and POWER) and lift the principles to a straightforward operational semantics which allows reasoning at a higher level of abstraction. To this end we introduce a wide-spectrum language that encompasses operations on abstract data types as well as low-level assembler code, define its operational semantics using a novel approach to allowing reordering of instructions, and derive some refinement laws that can be used to explain behaviours of real processors. In this framework memory models are mostly distinguished via a pair-wise static ordering on instruction types that determines when later instructions may be reordered before earlier instructions. In addition, memory models may use different types of storage systems. For instance, non-multicopy atomic systems allow sibling processes to see updates to different variables in different orders.
We encode the semantics in the rewriting engine Maude as a model-checking tool, and develop confidence in our framework by validating our semantics against existing sets of \textit{litmus tests} -- small assembler programs -- comparing our results with those observed on hardware and in existing semantics. We also use the tool as a prototype to model check implementations of data structures from the literature against their abstract specifications.
△ Less
Submitted 2 December, 2018;
originally announced December 2018.
-
Correctness of Concurrent Objects under Weak Memory Models
Authors:
Graeme Smith,
Kirsten Winter,
Robert J. Colvin
Abstract:
In this paper we develop a theory for correctness of concurrent objects under weak memory models. Central to our definitions is the concept of observations which determine when effects of operations become visible, and hence determine the semantics of objects, under a given memory model. The resulting notion of correctness, called object refinement, is generic as it is parameterised by the memory…
▽ More
In this paper we develop a theory for correctness of concurrent objects under weak memory models. Central to our definitions is the concept of observations which determine when effects of operations become visible, and hence determine the semantics of objects, under a given memory model. The resulting notion of correctness, called object refinement, is generic as it is parameterised by the memory model under consideration. Our theory enforces the minimal constraints on the placing of observations and on the semantics of objects that underlie object refinement. Object refinement is suitable as a reference for correctness when proving new proof methods for objects under weak memory models to be sound and complete.
△ Less
Submitted 22 October, 2018;
originally announced October 2018.
-
A sound and complete definition of linearizability on weak memory models
Authors:
Graeme Smith,
Kirsten Winter,
Robert J. Colvin
Abstract:
Linearizability is a widely accepted notion of correctness for concurrent objects. Recent research has investigated redefining linearizability for particular hardware weak memory models, in particular for TSO. In this paper, we provide an overview of this research and show that such redefinitions of linearizability are not required: under an interpretation of specification behaviour which abstract…
▽ More
Linearizability is a widely accepted notion of correctness for concurrent objects. Recent research has investigated redefining linearizability for particular hardware weak memory models, in particular for TSO. In this paper, we provide an overview of this research and show that such redefinitions of linearizability are not required: under an interpretation of specification behaviour which abstracts from weak memory effects, the standard definition of linearizability is sound and complete on all hardware weak memory models. We prove our result with respect to a definition of object refinement which takes a weak memory model as a parameter. The main consequence of our findings is that we can leverage the range of existing techniques and tools for standard linearizability when verifying concurrent objects running on hardware weak memory models.
△ Less
Submitted 1 July, 2019; v1 submitted 13 February, 2018;
originally announced February 2018.
-
A wide-spectrum language for verification of programs on weak memory models
Authors:
Robert J. Colvin,
Graeme Smith
Abstract:
Modern processors deploy a variety of weak memory models, which for efficiency reasons may (appear to) execute instructions in an order different to that specified by the program text. The consequences of instruction reordering can be complex and subtle, and can impact on ensuring correctness. Previous work on the semantics of weak memory models has focussed on the behaviour of assembler-level pro…
▽ More
Modern processors deploy a variety of weak memory models, which for efficiency reasons may (appear to) execute instructions in an order different to that specified by the program text. The consequences of instruction reordering can be complex and subtle, and can impact on ensuring correctness. Previous work on the semantics of weak memory models has focussed on the behaviour of assembler-level programs. In this paper we utilise that work to extract some general principles underlying instruction reordering, and apply those principles to a wide-spectrum language encompassing abstract data types as well as low-level assembler code. The goal is to support reasoning about implementations of data structures for modern processors with respect to an abstract specification.
Specifically, we define an operational semantics, from which we derive some properties of program refinement, and encode the semantics in the rewriting engine Maude as a model-checking tool. The tool is used to validate the semantics against the behaviour of a set of litmus tests (small assembler programs) run on hardware, and also to model check implementations of data structures from the literature against their abstract specifications.
△ Less
Submitted 12 February, 2018;
originally announced February 2018.
-
A synchronous program algebra: a basis for reasoning about shared-memory and event-based concurrency
Authors:
Ian J. Hayes,
Larissa A. Meinicke,
Kirsten Winter,
Robert J. Colvin
Abstract:
This research started with an algebra for reasoning about rely/guarantee concurrency for a shared memory model. The approach taken led to a more abstract algebra of atomic steps, in which atomic steps synchronise (rather than interleave) when composed in parallel. The algebra of rely/guarantee concurrency then becomes an instantiation of the more abstract algebra. Many of the core properties neede…
▽ More
This research started with an algebra for reasoning about rely/guarantee concurrency for a shared memory model. The approach taken led to a more abstract algebra of atomic steps, in which atomic steps synchronise (rather than interleave) when composed in parallel. The algebra of rely/guarantee concurrency then becomes an instantiation of the more abstract algebra. Many of the core properties needed for rely/guarantee reasoning can be shown to hold in the abstract algebra where their proofs are simpler and hence allow a higher degree of automation. The algebra has been encoded in Isabelle/HOL to provide a basis for tool support for program verification.
In rely/guarantee concurrency, programs are specified to guarantee certain behaviours until assumptions about the behaviour of their environment are violated. When assumptions are violated, program behaviour is unconstrained (aborting), and guarantees need no longer hold. To support these guarantees a second synchronous operator, weak conjunction, was introduced: both processes in a weak conjunction must agree to take each atomic step, unless one aborts in which case the whole aborts. In developing the laws for parallel and weak conjunction we found many properties were shared by the operators and that the proofs of many laws were essentially the same. This insight led to the idea of generalising synchronisation to an abstract operator with only the axioms that are shared by the parallel and weak conjunction operator, so that those two operators can be viewed as instantiations of the abstract synchronisation operator. The main differences between parallel and weak conjunction are how they combine individual atomic steps; that is left open in the axioms for the abstract operator.
△ Less
Submitted 9 October, 2017;
originally announced October 2017.
-
Designing a semantic model for a wide-spectrum language with concurrency
Authors:
Robert J. Colvin,
Ian J. Hayes,
Larissa A. Meinicke
Abstract:
A wide-spectrum language integrates specification constructs into a programming language in a manner that treats a specification command just like any other command. This paper investigates a semantic model for a wide-spectrum language that supports concurrency and a refinement calculus. In order to handle specifications with rely and guarantee conditions, the model includes explicit environment s…
▽ More
A wide-spectrum language integrates specification constructs into a programming language in a manner that treats a specification command just like any other command. This paper investigates a semantic model for a wide-spectrum language that supports concurrency and a refinement calculus. In order to handle specifications with rely and guarantee conditions, the model includes explicit environment steps as well as program steps. A novelty of our approach is that we define a set of primitive commands and operators, from which more complex specification and programming language commands are built. The primitives have simple algebraic properties which support proof using algebraic reasoning. The model is general enough to specify notions as diverse as rely-guarantee reasoning, temporal logic, and progress properties of programs, and supports refining specifications to code. It also forms an instance of an abstract concurrent program algebra, which facilitates reasoning about properties of the model at a high level of abstraction.
△ Less
Submitted 1 September, 2016;
originally announced September 2016.