Verifying Concurrent Processes Using Temporal Logic

Concurrent processes can exhibit extremely complicated behavior, and neither informal reasoning nor testing is reliable enough to establish their correctness. In this thesis, we develop a new technique for the verification of parallel programs. The technique is stated in terms of axioms and inference rules, and it is used to prove safety and liveness properties of parallel programs. Safety properties are assertions that must be satisfied by the system state at all times; they are analogous to partial correctness. Liveness properties refer to events that will occur in the future, such as program termination or the eventual receipt of a message. In addition to the formal proof rules, we present several heuristics to aid in the preparation of correctness proofs. We model a parallel program as a set of interacting modules (processes and monitors), and we exploit this modularity in the verification process. First we prove properties of the low-level modules directly from their code. We then combine the specifications of the low-level modules to prove properties of higher-level modules, without again referring to the code. Eventually, we prove properties of the entire program. We discuss the application of this verification technique to two classes of parallel programs: network protocols and resource allocators. Most previous approaches to verifying network protocols have been based upon reachability arguments for finite-state models of the protocols. Only protocols of limited complexity can be verified using the finite-state model, because of the combinatorial explosion of the state space as the complexity of the protocol increases. In contrast, our approach allows us to abstract information from the details of the implementation, so that the proof need not grow unmanageably as the protocol size increases. The discussion of resource allocation centers around Hoare's structured paging system, which is a complex hierarchical program. With this example, we demonstrate that many of the techniques used in program verification can be used for specification as well. The thesis also describes a number of tools that have been useful in proving concurrent programs. Two of the most important are history variables and temporal logic. We employ history variables to record the interaction between the modules that constitute a program. Temporal logic serves as a convenient notation for stating and proving liveness properties.