Saffire
Static Analysis of Foreign Function InteRfacEs

Overview

Saffire is a static analysis program that detects bugs in programs that use the OCaml/C foreign function interface. Saffire works by performing type inference across both OCaml and C to make sure that values are used consistently across the language boundary. For instance, if a OCaml passes a record to a C function, that C function should not treat the data as an integer. Saffire also tracks what C variables point into the OCaml heap and ensure they are always registered with CAMLparam/local before any allocation functions are called.

In the OCaml FFI, C is able to view OCaml data at a very low level and a single C value could represent several OCaml types. For instance, the value Val_int(0) could represent ():unit or false:bool since they are represented identically in memory. C programs also perform pattern matching using tag tests and compute offsets into OCaml data blocks.

Saffire analyzes a program using a combination of dataflow analysis and type inference with representational types, which are based on the physical representation of a type in memory. The analysis tracks what possible integer elements (unboxed data) a type could have, and the size and shape of the boxed (pointer) data.

The first step in Saffire's analysis is to parse OCaml source files and pull out all of the external definitions. Saffire records these in an offline store and later converts all of the OCaml types into representational types. Next, Saffire parses the C source code and performs type inference and dataflow analysis to determine the representational types used there. The types from the first step are used as a starting point for C functions declared external in OCaml. A more complete description of Saffire is described in our upcoming PLDI paper.

What's Supported:

Saffire is currently only a proof of concept implementation and does not handle every corner of the OCaml grammar. If you find that Saffire can't handle your code, drop me an email and I'll try to add support for it. Most common constructs and operations are supported:

What's NOT Supported:

Use of the following features of OCaml may result in warnings from Saffire, even if they are used safely.

Download

Saffire is based on CIL and requires OCaml version >= 3.08.0. Unfortunately, we had to apply a few small patches to the CIL core and thus our tool is distributed simply as a hacked CIL source tree. Both CIL and our work are licensed under the standard 3-clause BSD license.
The most recent release is 0.0.20050502.
Grab it here: saffire-cil-0.0.20050502.tar.gz [GPG sig]

Building

In order to build Saffire, just run
./configure
make

Installation

The FFI type checker does not currently support installing into another location at this time. Therefore you have to use it from within its build directory.

To do this, simply add the bin/ directory in the build tree to your path:
export PATH=$PATH:/path/to/saffire-cil/bin

Usage

Here is the basic overview of how to use our tool:

  1. Copy saffire-cil/lib/saffire/system.type_store.saffire to your_project/src/type_store.saffire. This file contains the types from OCaml's standard library and is updated when analyzing a project
  2. Hack your build system (Makefile,etc...) to use the OCaml wrappers to compile and link your OCaml source files
  3. Hack your build system (Makefile,etc...) to use the C wrappers to compile your C source files
  4. Compile your OCaml files (this updates type_store.saffire)
  5. Compile your C files (this reads type_store.saffire and thus should be done after step 4)
  6. Examine saffire.checks to see if any warnings were produced

Compiler wrappers

Shipped in the bin directory are several wrappers that attempt to make using the tool a little easier.

Example

As an example, download this program. Then follow these steps to analyze it:

  1. Unpack the tarball: tar zxfv saffire-example.tar.gz
  2. Copy saffire-cil/lib/saffire/system.type_store.saffire to saffire-example/type_store.saffire
  3. Edit the Makefile (a separate file, "Makefile.instrumented" is also included which contains these changes):
  4. Update your PATH:
    export PATH=$PATH:/path/to/saffire-cil-VERSION/bin
  5. run "make"
  6. Look at "saffire.checks" to see the errors it reported

Saffire produced two errors in "saffire.checks" for this code. The first error is because f1 is passed a pair of integers, but treats them as a single integer. The second error is because the variable w points to the pair of integers passed to f2. If the call to caml_alloc() were to cause a garbage collection, this value may be moved and the location stored in w would not be updated. Note that v2 is now shown in the error message because it is not live at the call to indirect_alloc().

Common error messages:


Mike Furr