CITRUS: C++ Unit Testing for Real-world Usage

Introduction

CITRUS is an implementation of Unit-level Testing for C++ based on random method call sequence generation.

CITRUS automatically generates test driver files for the target program P, each of which consists of various method calls of P. In addition, CITRUS improves the test coverage of P further by applying libfuzzer to change P’s state by mutating arguments of the methods.

For more details, please refer to CITRUS technical paper.

Requirements

CITRUS was tested running on Ubuntu 16.04, 18.04, 20.04. The requirements of CITRUS are:

  1. LLVM/Clang++ 11.0.1,
  2. LCOV coverage measurement tool (we used a modified LCOV for CITRUS development),
  3. CMake 3.15,
  4. Python 3.

We provide a shell script to install all CITRUS requirements. (root privilege required)

./scripts/dep.sh

Build Instruction

To build CITRUS is simply executing the build script

./scripts/build.sh

CITRUS will be built in build directory.

Building CITRUS Subjects

We provide the target programs we use for our experiment at replication directory. For simplicity, you can execute the following shell script (from the CITRUS root project directory) to build all our experiments subjects.

./scripts/bootstrap.sh subjects             # to build in subjects dir

Running CITRUS Method Call Sequence Generation

Currently CITRUS only supports command-line interface.

./build/citrus ${TRANS_UNIT} \
  --obj-dir ${OBJ_DIR} \
  --src-dir ${SRC_DIR} \
  --max-depth ${MAX_DEPTH} \
  --fuzz-timeout ${TIMEOUT} \
  --xtra-ld "${XTRA_LD}" \
  --out-prefix ${OUT_PREFIX}

For easier usage, we recommend to write separate shell script(s) to configure the command-line arguments as demonstrated in run directory. For example, to run CITRUS on hjson library:

./run/hjson.sh 43200 tc_hjson subjects/hjson-cpp          # 12 hours

where tc_hjson represents the target directory where the generated test cases will be put at, and subjects/hjson-cpp represents the hjson directory.

Running CITRUS libfuzzer

Currently the libfuzzer stage must be manually triggered after the method call sequence generation. CITRUS writes the libfuzzer harness drivers in out_libfuzzer directory. Each driver has compilation instruction at the end of the file.

To ease the libfuzzer stage, we provide batch_libfuzzer.py script (i.e., CITRUS already puts this script in out_libfuzzer directory) to collect all compilation, running, and test case replaying instructions for libfuzzer stage.

# Compilation (from out_libfuzzer directory)
python3 batch_libfuzzer gen             # initializes the scripts
./tst_compile.sh                        # compile all harness drivers

# Running libfuzzer
./tst_run.sh                            # default: 5 mins each driver

# Replaying libfuzzer generated test cases
./tst_repl.sh                           

Developed by SWTV Lab, KAIST