Runtime Verification of C Memory Safety

C is the most widely used imperative system's implementation language. While C provides types and high-level abstractions, its design goal has been to provide highest performance which often requires low-level access to memory. As a consequence C supports arbitrary pointer arithmetic, casting, and explicit allocation and deallocation. These operations are difficult to use, resulting in programs that often have software bugs like buffer overflows and dangling pointers that cause security vulnerabilities. We say a C program is memory safe, if at runtime it never goes wrong with such a memory access error. Based on standards for writing "good" C code, this paper proposes strong memory safety as the least restrictive formal definition of memory safety amenable for runtime verification. We show that although verification of memory safety is in general undecidable, even when restricted to closed, terminating programs, runtime verification of strong memory safety is a decision procedure for this class of programs. We verify strong memory safety of a program by executing the program using a symbolic, deterministic definition of the dynamic semantics. A prototype implementation of these ideas shows the feasibility of this approach.

[1]  D. C. Cooper,et al.  Theory of Recursive Functions and Effective Computability , 1969, The Mathematical Gazette.

[2]  Jr. Hartley Rogers Theory of Recursive Functions and Effective Computability , 1969 .

[3]  Guy L. Steele,et al.  C, a reference manual , 1984 .

[4]  Robert O. Hastings,et al.  Fast detection of memory leaks and access errors , 1991 .

[5]  José Meseguer,et al.  Conditioned Rewriting Logic as a United Model of Concurrency , 1992, Theor. Comput. Sci..

[6]  Matthias Felleisen,et al.  A Syntactic Approach to Type Soundness , 1994, Inf. Comput..

[7]  Michal Walicki,et al.  Algebraic approaches to nondeterminism—an overview , 1997, CSUR.

[8]  George C. Necula,et al.  CCured: type-safe retrofitting of legacy code , 2002, POPL '02.

[9]  Emery D. Berger,et al.  DieHard: probabilistic memory safety for unsafe languages , 2006, PLDI '06.

[10]  Nicholas Nethercote,et al.  Valgrind: a framework for heavyweight dynamic binary instrumentation , 2007, PLDI '07.

[11]  José Meseguer,et al.  The Rewriting Logic Semantics Project , 2006, SOS@ICALP.

[12]  Grigore Rosu,et al.  K: A Rewriting-Based Framework for Computations -- Preliminary version -- , 2007 .

[13]  Narciso Martí-Oliet,et al.  All About Maude - A High-Performance Logical Framework, How to Specify, Program and Verify Systems in Rewriting Logic , 2007, All About Maude.

[14]  Emery D. Berger,et al.  Exterminator: automatically correcting memory errors with high probability , 2007, PLDI '07.

[15]  José Meseguer,et al.  A rewriting logic approach to operational semantics , 2009, Inf. Comput..