Source Code

The source code is available here: https://github.com/davidtr1037/klee-ram.

Replication Package

Environment

The experiments were run on a Ubuntu 16.04 machine, with Intel i7-6700 processor (8 cores) and 32GB of RAM. Note that building LLVM takes usually 15-30 minutes (depending on your hardware and how many cores you use), so please take that into consideration. The rest of the dependencies are built relatively quickly.

Build & Install

Install the following packages, using:

sudo apt-get install cmake bison flex libboost-all-dev python perl zlib1g-dev build-essential curl libcap-dev git cmake libncurses5-dev python-minimal python-pip unzip libtcmalloc-minimal4 libgoogle-perftools-dev libsqlite3-dev doxygen
pip3 install tabulate wllvm

LLVM 7.0

wget https://releases.llvm.org/7.0.0/llvm-7.0.0.src.tar.xz
wget https://releases.llvm.org/7.0.0/cfe-7.0.0.src.tar.xz
wget https://releases.llvm.org/7.0.0/compiler-rt-7.0.0.src.tar.xz
tar xJf llvm-7.0.0.src.tar.xz
tar xJf cfe-7.0.0.src.tar.xz
tar xJf compiler-rt-7.0.0.src.tar.xz
mv cfe-7.0.0.src llvm-7.0.0.src/tools/clang
mv compiler-rt-7.0.0.src compiler-rt
mkdir llvm-7.0.0.obj
cd llvm-7.0.0.obj
cmake CMAKE_BUILD_TYPE:STRING=Release -DLLVM_ENABLE_THREADS:BOOL=ON -DLLVM_ENABLE_PROJECTS:STRING=compiler-rt ../llvm-7.0.0.src
make -j4

Update the following variables:

export PATH=<llvm_build_dir>/bin:$PATH
export LLVM_COMPILER=clang

minisat

git clone https://github.com/stp/minisat.git
cd minisat
mkdir build
cd build
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/ ../
sudo make install

STP

git clone https://github.com/stp/stp.git
cd stp
git checkout tags/2.3.3
mkdir build
cd build
cmake ..
make
sudo make install

klee-uclibc

git clone https://github.com/klee/klee-uclibc.git
cd klee-uclibc
git checkout 038b7dc050c07a7b4d941b48a0f548eea3089214
./configure --make-llvm-lib
make
cd ..

In the paper we used 3 versions of KLEE:

  • Baseline KLEE
  • SMM
  • Our extension

To build those, first clone our repository:

git clone git@github.com:davidtr1037/klee-ram.git <klee_dir>

Building Baseline KLEE

git checkout issta-vanilla
mkdir vanilla-build
cd vanilla-build
CXXFLAGS="-fno-rtti" cmake \
    -DENABLE_SOLVER_STP=ON \
    -DENABLE_POSIX_RUNTIME=ON \
    -DENABLE_KLEE_UCLIBC=ON \
    -DKLEE_UCLIBC_PATH=<klee_uclibc_dir> \
    -DLLVM_CONFIG_BINARY=<llvm_build_dir>/bin/llvm-config \
    -DLLVMCC=<llvm_build_dir>/bin/clang \
    -DLLVMCXX=<llvm_build_dir>/bin/clang++ \
    -DENABLE_UNIT_TESTS=OFF \
    -DKLEE_RUNTIME_BUILD_TYPE=Release+Asserts \
    -DENABLE_SYSTEM_TESTS=ON \
    -DENABLE_TCMALLOC=ON \
    ..
make

Building SMM KLEE

First, build SVF:

git clone https://github.com/kren1/SVF.git <svf-dir>
cd <svf-dir>
git checkout fix_pta_delete
mkdir build
cd build
LLVM_DIR=../../llvm-7.0.0.obj/ cmake ..
make
cp lib/Svf.so lib/libSvf.so
cp lib/CUDD/Cudd.so lib/CUDD/libCudd.so

And then:

git checkout segmented_mem7.0
mkdir smm-build
cd smm-build
CXXFLAGS="-fno-rtti" cmake \
    -DENABLE_SOLVER_STP=ON \
    -DENABLE_POSIX_RUNTIME=ON \
    -DENABLE_KLEE_UCLIBC=ON \
    -DKLEE_UCLIBC_PATH=<klee_uclibc_dir> \
    -DLLVM_CONFIG_BINARY=<llvm_build_dir>/bin/llvm-config \
    -DLLVMCC=<llvm_build_dir>/bin/clang \
    -DLLVMCXX=<llvm_build_dir>/bin/clang++ \
    -DENABLE_UNIT_TESTS=OFF \
    -DKLEE_RUNTIME_BUILD_TYPE=Release+Asserts \
    -DENABLE_SYSTEM_TESTS=ON \
    -DENABLE_TCMALLOC=ON \
    -DSVF_ROOT_DIR=<svf-dir> \
    ..
make

Building our tool

To build our tool which is an extension of KLEE, do the following:

git checkout issta-tool
mkdir tool-build
cd tool-build
CXXFLAGS="-fno-rtti" cmake \
    -DENABLE_SOLVER_STP=ON \
    -DENABLE_POSIX_RUNTIME=ON \
    -DENABLE_KLEE_UCLIBC=ON \
    -DKLEE_UCLIBC_PATH=<klee_uclibc_dir> \
    -DLLVM_CONFIG_BINARY=<llvm_build_dir>/bin/llvm-config \
    -DLLVMCC=<llvm_build_dir>/bin/clang \
    -DLLVMCXX=<llvm_build_dir>/bin/clang++ \
    -DENABLE_UNIT_TESTS=OFF \
    -DKLEE_RUNTIME_BUILD_TYPE=Release+Asserts \
    -DENABLE_SYSTEM_TESTS=ON \
    -DENABLE_TCMALLOC=ON \
    <klee_dir>
make

Update the PATH variable:

export PATH=<klee-dir>/tool-build/bin:$PATH

Usage and example

Our tool is an extension of KLEE, to which we added several new command line options. The main options are:

  • use-sym-addr: use the addressing model described in the paper (section 2.2)
  • use-rebase: enable dynamic merging of memory objects (section 2.3)
  • split-objects: enable dynamic splitting of memory objects (section 2.4)
  • split-threshold=N: split objects larger than N bytes (section 2.4)
  • partition-size=N: set the size of the split objects (section 2.4)

For a simple example, we provide the following C program:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <klee/klee.h>

#define N (4)

typedef struct {
    int k;
    char data[512];
} object_t;

int main(int argc, char *argv[]) {
    object_t **array = calloc(N, sizeof(object_t *));
    for (unsigned int i = 0; i < N; i++) {
        array[i] = calloc(sizeof(object_t), 1);
    }

    unsigned int i = klee_range(0, N, "i");
    if (array[i]->k == 0) {
        printf("OK\n");
    }

    unsigned int k = klee_range(0, N, "k");
    if (array[k]->k == 0) {
        printf("OK\n");
    }

    return 0;
}

Analyzing with baseline KLEE:

klee -libc=uclibc -search=dfs -allocate-determ -allocate-determ-start-address=0x0 <bitcode_file>

Analyzing with our addressing model with merging:

klee -libc=uclibc -search=dfs -allocate-determ -allocate-determ-start-address=0x0 -use-sym-addr -use-rebase <bitcode_file>

Analyzing with our addressing model with splitting:

klee -libc=uclibc -search=dfs -allocate-determ -allocate-determ-start-address=0x0 -use-sym-addr -split-objects -split-threshold=128 -partition-size=64 <bitcode_file>

Benchmarks

First, clone the benchmarks repository:

git clone https://github.com/davidtr1037/klee-mm-benchmarks <benchmarks-dir>

Build the .bc files:

cd <benchmarks-dir>/m4
make all
cd <benchmarks-dir>/make
make all
cd <benchmarks-dir>/sqlite
make all
cd <benchmarks-dir>/apr
make test_driver.bc
cd <benchmarks-dir>/binutils
make all
cd <benchmarks-dir>/libxml2
make test_driver.bc
cd <benchmarks-dir>/coreutils
make all
./extract.sh

Traces

We provide the traces for our experiments, which can be downloaded from here: https://doi.org/10.6084/m9.figshare.12625109. The traces are the klee_out directories generated by KLEE.

Section 4.1:

python <benchmarks-dir>/parse_overhead.py traces/overhead

The directory traces/overhead contains output directories of the form:

  • out-klee-<program> (baseline)
  • out-mm-<program> (our addressing model)

Table 3:

The directory traces/merge/models contains output directories of the form out-mode-search.

python <benchmarks-dir>/parse_models.py traces/merge/models

Table 4:

The directory traces/merge/resolve-queries contains output directories of the form out-kN (for N=0,1,2,3,4) and out-default.

python <benchmarks-dir>/parse_resolve_queries.py traces/merge/resolve-queries

Table 5:

The directory traces/merge/optimizations contains output directories of the form out-no-opt, out-opt-context, out-opt-reuse.

python <benchmarks-dir>/parse_opts.py traces/merge/optimizations

Table 7:

The directory traces/split contains output directories of the form out-split-pN (for N=32,64,128,256,512) and out-split-vanilla.

python <benchmarks-dir>/parse_opts.py traces/split

Experiments

Configuration

First, initialize the output directory which will contain the results of the experiments (klee-out directories):

<benchmarks-dir>/init_artifact_dir.sh <full-path-to-new-output-dir>

Before running the experiments, we will need to set some variables in <benchmarks-dir>/config.sh:

VANILLA_KLEE=<vanilla-build-dir>/bin/klee
KLEE_SMM=<smm-build-dir>/bin/klee
KLEE=<tool-build-dir>/bin/klee
ARTIFACT_DIR=<full-path-to-new-output-dir>

Correctness and overhead

Run the following command:

<benchmarks-dir>/run_overhead_all.sh

To parse the results:

python <benchmarks-dir>/parse_overhead.py <full-path-to-new-output-dir>/overhead

Merging

For the experiment related to Table 3, we run in 3 different memory models: Forking memory model:

<benchmarks-dir>/run_fmm_all.sh

Segmented memory model:

<benchmarks-dir>/run_smm_all.sh

Dynamically segmented memory model:

<benchmarks-dir>/run_dsmm_all.sh

To parse the results:

python <benchmarks-dir>/parse_models.py <full-path-to-new-output-dir>/merge/models

Resolution Queries

For the experiment related to Table 4, do the following:

<benchmarks-dir>/run_resolve_all.sh

To parse the results:

python <benchmarks-dir>/parse_resolve_queries.py <full-path-to-new-output-dir>/merge/resolve-queries

Optimizations

For the experiment related to Table 5, do the following:

<benchmarks-dir>/run_opts_all.sh

To parse the results:

python <benchmarks-dir>/parse_opts.py <full-path-to-new-output-dir>/merge/optimizations

Splitting

For the experiment related to Table 7, do the following:

<benchmarks-dir>/run_split_all.sh

To parse the results:

python <benchmarks-dir>/parse_opts.py <full-path-to-new-output-dir>/split