Update README.md

This commit is contained in:
Robert Sebastian Herlim 2021-10-09 13:44:00 +09:00
parent e27ed026dd
commit 78396dcb3b
10 changed files with 87 additions and 72 deletions

View File

@ -1,9 +1,82 @@
# CITRUS: C++ Unit Testing for Real-world Usage # CITRUS: C++ Unit Testing for Real-world Usage
CITRUS is an implementation of Unit-level Fuzzing for C++ based on random method sequence generation. ## Introduction
Implemented using C++14 and backporting library to utilize C++17's `std::optional` feature.
Tested working on: Ubuntu 16.04, 18.04, 20.04 using LLVM/Clang++ 11.0.1 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
Developed by SWTV Lab, KAIST 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,
1. LCOV coverage measurement tool (we used a [modified LCOV](https://github.com/henry2cox/lcov/tree/diffcov_initial) for CITRUS development),
1. CMake 3.15,
1. Python 3.
We provide a shell script to install all CITRUS requirements. (**root privilege required**)
```shell
./scripts/dep.sh
```
## Build Instruction
To build CITRUS is simply executing the build script
```shell
./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.
```shell
./scripts/bootstrap.sh subjects # to build in subjects dir
```
## Running CITRUS Method Call Sequence Generation
Currently CITRUS only supports command-line interface.
```shell
./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:
```shell
./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.
```shell
# 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**

View File

@ -5,11 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
#USE_FUNC_COMP=$2
#FUNC_COMP=
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/all.cpp TRANS_UNIT=${SUBJ_DIR}/all.cpp
OBJ_DIR=${SUBJ_DIR} OBJ_DIR=${SUBJ_DIR}
@ -28,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,12 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
FUNC_COMP=__none.txt
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/hjson.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/src/hjson_encode.cpp TRANS_UNIT=${SUBJ_DIR}/src/hjson_encode.cpp
OBJ_DIR=${SUBJ_DIR}/build/src/CMakeFiles/hjson.dir OBJ_DIR=${SUBJ_DIR}/build/src/CMakeFiles/hjson.dir
@ -29,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,11 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/json-voorhees.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/src/jsonv/all.cpp TRANS_UNIT=${SUBJ_DIR}/src/jsonv/all.cpp
OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/jsonv.dir/src/jsonv OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/jsonv.dir/src/jsonv
@ -28,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,11 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/jsonbox.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/src/all.cpp TRANS_UNIT=${SUBJ_DIR}/src/all.cpp
OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/JsonBox.dir/src OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/JsonBox.dir/src
@ -28,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,12 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
FUNC_COMP=__none.txt
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/jsoncpp.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/src/lib_json/all.cpp TRANS_UNIT=${SUBJ_DIR}/src/lib_json/all.cpp
OBJ_DIR=${SUBJ_DIR}/build/src/lib_json/CMakeFiles/jsoncpp_lib.dir OBJ_DIR=${SUBJ_DIR}/build/src/lib_json/CMakeFiles/jsoncpp_lib.dir
@ -29,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,11 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/jvar.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/src/all.cpp TRANS_UNIT=${SUBJ_DIR}/src/all.cpp
OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/jvar.dir/src OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/jvar.dir/src
@ -28,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,11 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/re2.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/re2/all.cpp TRANS_UNIT=${SUBJ_DIR}/re2/all.cpp
OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/re2.dir/ OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/re2.dir/
@ -28,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,12 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
FUNC_COMP=__none.txt
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/tinyxml2.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/tinyxml2.cpp TRANS_UNIT=${SUBJ_DIR}/tinyxml2.cpp
OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/tinyxml2.dir OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/tinyxml2.dir
@ -29,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}

View File

@ -5,12 +5,6 @@ TARGET=build/citrus
TIMEOUT=$1 TIMEOUT=$1
OUT_PREFIX=$2 OUT_PREFIX=$2
SUBJ_DIR=$3 SUBJ_DIR=$3
FUNC_COMP=__none.txt
#USE_FUNC_COMP=$2
#FUNC_COMP=func_comp/re2.txt
#if [[ "${USE_FUNC_COMP^^}" == "NO" ]]; then
# FUNC_COMP=__none.txt
#fi
TRANS_UNIT=${SUBJ_DIR}/src/all.cpp TRANS_UNIT=${SUBJ_DIR}/src/all.cpp
OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/yaml-cpp.dir/src OBJ_DIR=${SUBJ_DIR}/build/CMakeFiles/yaml-cpp.dir/src
@ -29,5 +23,4 @@ ${TARGET} ${TRANS_UNIT} \
--max-depth ${MAX_DEPTH} \ --max-depth ${MAX_DEPTH} \
--fuzz-timeout ${TIMEOUT} \ --fuzz-timeout ${TIMEOUT} \
--xtra-ld "${XTRA_LD}" \ --xtra-ld "${XTRA_LD}" \
--out-prefix ${OUT_PREFIX} \ --out-prefix ${OUT_PREFIX}
--func-comp ${FUNC_COMP}