================================================
FILE: CMakeLists.txt
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
###############################################################################
# Minimum CMake version and policies
###############################################################################
cmake_minimum_required(VERSION 2.8.12)
if (POLICY CMP0054)
# FIXME: This is horrible. With the old behaviour,
# quoted strings like "MSVC" in if() conditionals
# get implicitly dereferenced. The NEW behaviour
# doesn't do this but CMP0054 was only introduced
# in CMake 3.1 and we support lower versions as the
# minimum. We could set NEW here but it would be very
# confusing to use NEW for some builds and OLD for others
# which could lead to some subtle bugs. Instead when the
# minimum version is 3.1 change this policy to NEW and remove
# the hacks in place to work around it.
cmake_policy(SET CMP0054 OLD)
endif()
if (POLICY CMP0042)
# Enable `MACOSX_RPATH` by default.
cmake_policy(SET CMP0042 NEW)
endif()
if (POLICY CMP0037)
# Disallow reserved target names
cmake_policy(SET CMP0037 NEW)
endif()
# This overrides the default flags for the different CMAKE_BUILD_TYPEs
set(CMAKE_USER_MAKE_RULES_OVERRIDE_C
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/c_flags_override.cmake")
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cxx_flags_override.cmake")
project(JFS CXX C)
###############################################################################
# Project version
###############################################################################
set(JFS_VERSION_MAJOR 0)
set(JFS_VERSION_MINOR 0)
set(JFS_VERSION_PATCH 0)
set(JFS_VERSION_TWEAK 0)
set(JFS_VERSION "${JFS_VERSION_MAJOR}.${JFS_VERSION_MINOR}.${JFS_VERSION_PATCH}.${JFS_VERSION_TWEAK}")
message(STATUS "JFS version ${JFS_VERSION}")
################################################################################
# Set various useful variables depending on CMake version
################################################################################
if (("${CMAKE_VERSION}" VERSION_EQUAL "3.2") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.2"))
# In CMake >= 3.2 add_custom_command() supports a ``USES_TERMINAL`` argument
set(ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG "USES_TERMINAL")
else()
set(ADD_CUSTOM_COMMAND_USES_TERMINAL_ARG "")
endif()
if (("${CMAKE_VERSION}" VERSION_EQUAL "3.4") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.4"))
# In CMake >= 3.4 ExternalProject_Add_Step() supports a `USES_TERMINAL` argument
set(EXTERNAL_PROJECT_ADD_STEP_USES_TERMINAL_ARG "USES_TERMINAL" "1")
else()
set(EXTERNAL_PROJECT_ADD_STEP_USES_TERMINAL_ARG "")
endif()
################################################################################
# Sanity check - Disallow building in source.
################################################################################
if ("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_BINARY_DIR}")
message(FATAL_ERROR "In source builds are not allowed. You should invoke "
"CMake from a different directory.")
endif()
################################################################################
# Build type
################################################################################
message(STATUS "CMake generator: ${CMAKE_GENERATOR}")
if (DEFINED CMAKE_CONFIGURATION_TYPES)
# Multi-configuration build (e.g. Xcode). Here
# CMAKE_BUILD_TYPE doesn't matter
message(STATUS "Available configurations: ${CMAKE_CONFIGURATION_TYPES}")
else()
# Single configuration generator (e.g. Unix Makefiles, Ninja)
set(available_build_types Debug Release RelWithDebInfo MinSizeRel)
if(NOT CMAKE_BUILD_TYPE)
message(STATUS "CMAKE_BUILD_TYPE is not set. Setting default")
message(STATUS "The available build types are: ${available_build_types}")
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE String
"Options are ${available_build_types}"
FORCE)
# Provide drop down menu options in cmake-gui
set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS ${available_build_types})
endif()
message(STATUS "Build type: ${CMAKE_BUILD_TYPE}")
# Check the selected build type is valid
list(FIND available_build_types "${CMAKE_BUILD_TYPE}" _build_type_index)
if ("${_build_type_index}" EQUAL "-1")
message(FATAL_ERROR "\"${CMAKE_BUILD_TYPE}\" is an invalid build type.\n"
"Use one of the following build types ${available_build_types}")
endif()
endif()
################################################################################
# Add our CMake module directory to the list of module search directories
################################################################################
list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake/modules")
################################################################################
# Compiler flags for JFS components
# Subsequent commands will append to these. These are used instead of
# directly modifying CMAKE_CXX_FLAGS so that other code can be easily built with
# different flags.
################################################################################
set(JFS_COMPONENT_EXTRA_INCLUDE_DIRS "")
set(JFS_COMPONENT_CXX_DEFINES "")
set(JFS_COMPONENT_CXX_FLAGS "")
set(JFS_SOLVER_LIBRARIES "")
set(JFS_COMPONENT_EXTRA_LIBRARIES "")
include("${CMAKE_SOURCE_DIR}/cmake/jfs_component_add_cxx_flag.cmake")
################################################################################
# JFS include directories
################################################################################
list(APPEND JFS_COMPONENT_EXTRA_INCLUDE_DIRS
"${CMAKE_BINARY_DIR}/include"
"${CMAKE_SOURCE_DIR}/include"
)
################################################################################
# Assertions
################################################################################
option(ENABLE_JFS_ASSERTS "Enable JFS assertions" ON)
if (ENABLE_JFS_ASSERTS)
message(STATUS "JFS assertions enabled")
# Assume that -DNDEBUG isn't set.
else()
message(STATUS "JFS assertions disabled")
list(APPEND JFS_COMPONENT_CXX_DEFINES "NDEBUG")
endif()
################################################################################
# Find LLVM
################################################################################
find_package(LLVM 6.0.0
CONFIG
)
set(NEEDED_LLVM_VARS
LLVM_PACKAGE_VERSION
LLVM_VERSION_MAJOR
LLVM_VERSION_MINOR
LLVM_VERSION_PATCH
LLVM_DEFINITIONS
LLVM_ENABLE_ASSERTIONS
LLVM_ENABLE_EH
LLVM_ENABLE_RTTI
LLVM_INCLUDE_DIRS
LLVM_LIBRARY_DIRS
LLVM_TOOLS_BINARY_DIR
)
foreach (vname ${NEEDED_LLVM_VARS})
message(STATUS "${vname}: \"${${vname}}\"")
if (NOT (DEFINED "${vname}"))
message(FATAL_ERROR "${vname} was not defined")
endif()
endforeach()
message(STATUS "LLVM_DIR: \"${LLVM_DIR}\"")
# Find Clang
# FIXME: This won't work if LLVM was built with a multi-configuration generator.
set(LLVM_CLANG_CXX_TOOL "${LLVM_TOOLS_BINARY_DIR}/clang++")
if (NOT EXISTS "${LLVM_CLANG_CXX_TOOL}")
message(FATAL_ERROR "Failed to find clang++ at \"${LLVM_CLANG_CXX_TOOL}\"")
else()
message(STATUS "Found clang++ at \"${LLVM_CLANG_CXX_TOOL}\"")
endif()
if (LLVM_ENABLE_ASSERTIONS)
# Certain LLVM debugging macros only work when LLVM was built with asserts
set(ENABLE_JFS_DEBUG 1) # for config.h
else()
unset(ENABLE_JFS_DEBUG) # for config.h
endif()
# LLVM_DEFINITIONS aren't lists. Instead they are space separated
string(REPLACE " " ";" LLVM_DEFINITIONS_AS_LIST "${LLVM_DEFINITIONS}")
list(APPEND JFS_COMPONENT_CXX_DEFINES ${LLVM_DEFINITIONS_AS_LIST})
# LLVM_INCLUDE_DIRS aren't lists. Instead they are space separated
string(REPLACE " " ";" LLVM_INCLUDE_DIRS_AS_LIST "${LLVM_INCLUDE_DIRS}")
list(APPEND JFS_COMPONENT_EXTRA_INCLUDE_DIRS ${LLVM_INCLUDE_DIRS_AS_LIST})
if (NOT LLVM_ENABLE_EH)
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
jfs_component_add_cxx_flag("-fno-exceptions" REQUIRED)
else()
message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} not supported")
endif()
endif()
if (NOT LLVM_ENABLE_RTTI)
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
jfs_component_add_cxx_flag("-fno-rtti" REQUIRED)
else()
message(FATAL_ERROR "${CMAKE_CXX_COMPILER_ID} not supported")
endif()
endif()
include("${CMAKE_SOURCE_DIR}/cmake/jfs_get_llvm_components.cmake")
################################################################################
# Find Z3
################################################################################
# FIXME: Specify version. Need to upstream support for config setting version.
find_package(Z3 CONFIG)
set(NEEDED_Z3_VARS
Z3_VERSION_MAJOR
Z3_VERSION_MINOR
Z3_VERSION_PATCH
Z3_VERSION_TWEAK
Z3_VERSION_STRING
Z3_C_INCLUDE_DIRS
Z3_LIBRARIES
)
foreach (vname ${NEEDED_Z3_VARS})
message(STATUS "${vname}: \"${${vname}}\"")
if (NOT (DEFINED "${vname}"))
message(FATAL_ERROR "${vname} was not defined")
endif()
endforeach()
if ("${Z3_VERSION_STRING}" VERSION_LESS "4.6")
message(FATAL_ERROR "Need Z3 4.6 or newer")
endif()
list(APPEND JFS_COMPONENT_EXTRA_INCLUDE_DIRS ${Z3_C_INCLUDE_DIRS})
################################################################################
# C++ version
################################################################################
# FIXME: Use CMake's support for this
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
set(JFS_USE_CXX_FLAG "-std=c++11")
jfs_component_add_cxx_flag("${JFS_USE_CXX_FLAG}" REQUIRED)
else()
set(JFS_USE_CXX_FLAG "")
endif()
################################################################################
# Warnings
################################################################################
include("${CMAKE_SOURCE_DIR}/cmake/compiler_warnings.cmake")
################################################################################
# Report flags
################################################################################
message(STATUS "JFS_COMPONENT_CXX_DEFINES: \"${JFS_COMPONENT_CXX_DEFINES}\"")
message(STATUS "JFS_COMPONENT_EXTRA_INCLUDE_DIRS: \"${JFS_COMPONENT_EXTRA_INCLUDE_DIRS}\"")
message(STATUS "JFS_COMPONENT_CXX_FLAGS: \"${JFS_COMPONENT_CXX_FLAGS}\"")
message(STATUS "JFS_COMPONENT_EXTRA_LIBRARIES: \"${JFS_COMPONENT_EXTRA_LIBRARIES}\"")
################################################################################
# Report default CMake flags
################################################################################
# This is mainly for debugging.
message(STATUS "CMAKE_CXX_FLAGS: \"${CMAKE_CXX_FLAGS}\"")
message(STATUS "CMAKE_EXE_LINKER_FLAGS: \"${CMAKE_EXE_LINKER_FLAGS}\"")
message(STATUS "CMAKE_STATIC_LINKER_FLAGS: \"${CMAKE_STATIC_LINKER_FLAGS}\"")
message(STATUS "CMAKE_SHARED_LINKER_FLAGS: \"${CMAKE_SHARED_LINKER_FLAGS}\"")
if (DEFINED CMAKE_CONFIGURATION_TYPES)
# Multi configuration generator
string(TOUPPER "${available_build_types}" build_types_to_report)
else()
# Single configuration generator
string(TOUPPER "${CMAKE_BUILD_TYPE}" build_types_to_report)
endif()
foreach (_build_type ${build_types_to_report})
message(STATUS "CMAKE_CXX_FLAGS_${_build_type}: \"${CMAKE_CXX_FLAGS_${_build_type}}\"")
message(STATUS "CMAKE_EXE_LINKER_FLAGS_${_build_type}: \"${CMAKE_EXE_LINKER_FLAGS_${_build_type}}\"")
message(STATUS "CMAKE_SHARED_LINKER_FLAGS_${_build_type}: \"${CMAKE_SHARED_LINKER_FLAGS_${_build_type}}\"")
message(STATUS "CMAKE_STATIC_LINKER_FLAGS_${_build_type}: \"${CMAKE_STATIC_LINKER_FLAGS_${_build_type}}\"")
endforeach()
################################################################################
# Handle git hash and description
################################################################################
include(${CMAKE_SOURCE_DIR}/cmake/git_utils.cmake)
macro(disable_git_describe)
message(WARNING "Disabling INCLUDE_GIT_DESCRIBE")
set(INCLUDE_GIT_DESCRIBE OFF CACHE BOOL "Include git describe output in version output" FORCE)
endmacro()
macro(disable_git_hash)
message(WARNING "Disabling INCLUDE_GIT_HASH")
set(INCLUDE_GIT_HASH OFF CACHE BOOL "Include git hash in version output" FORCE)
unset(Z3GITHASH) # Used in configure_file()
endmacro()
option(INCLUDE_GIT_HASH "Include git hash in version output" ON)
option(INCLUDE_GIT_DESCRIBE "Include git describe output in version output" ON)
set(GIT_DIR "${CMAKE_SOURCE_DIR}/.git")
if (EXISTS "${GIT_DIR}")
# Try to make CMake configure depend on the current git HEAD so that
# a re-configure is triggered when the HEAD changes.
add_git_dir_dependency("${GIT_DIR}" ADD_GIT_DEP_SUCCESS)
if (ADD_GIT_DEP_SUCCESS)
if (INCLUDE_GIT_HASH)
get_git_head_hash("${GIT_DIR}" JFS_GIT_HASH)
if (NOT JFS_GIT_HASH)
message(WARNING "Failed to get Git hash")
disable_git_hash()
endif()
message(STATUS "Using Git hash in version output: ${JFS_GIT_HASH}")
else()
message(STATUS "Not using Git hash in version output")
unset(JFS_GIT_HASH) # Used in configure_file()
endif()
if (INCLUDE_GIT_DESCRIBE)
get_git_head_describe("${GIT_DIR}" JFS_GIT_DESCRIPTION)
if (NOT Z3_GIT_DESCRIPTION)
message(WARNING "Failed to get Git description")
disable_git_describe()
endif()
message(STATUS "Using Git description in version output: ${JFS_GIT_DESCRIPTION}")
else()
message(STATUS "Not including git descrption in version")
endif()
else()
message(WARNING "Failed to add git dependency.")
disable_git_describe()
disable_git_hash()
endif()
else()
message(STATUS "Failed to find git directory.")
disable_git_describe()
disable_git_hash()
endif()
################################################################################
# Generate configuration header files
################################################################################
set(AUTO_GEN_MSG "Automatically generated. DO NOT EDIT")
set(configuration_files "version.h" "depsVersion.h" "config.h")
foreach (configuration_file ${configuration_files})
configure_file(
"${CMAKE_SOURCE_DIR}/include/jfs/Config/${configuration_file}.in"
"${CMAKE_BINARY_DIR}/include/jfs/Config/${configuration_file}"
)
endforeach()
################################################################################
# Set default location for targets in the build directory
################################################################################
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
################################################################################
# Top level unit test target
################################################################################
# This is top level because there are multiple unit test suites to run
add_custom_target(unittests)
################################################################################
# Detect lit tool
################################################################################
# This can't belong in `tests/` because `runtime/` needs to run its own tests.
option(ENABLE_SYSTEM_TESTS "Enable system tests" ON)
option(ENABLE_UNIT_TESTS "Enable unit tests" ON)
if (ENABLE_SYSTEM_TESTS OR ENABLE_UNIT_TESTS)
# Find lit
set(LIT_TOOL_NAMES "llvm-lit" "lit")
find_program(
LIT_TOOL
NAMES ${LIT_TOOL_NAMES}
HINTS "${LLVM_TOOLS_BINARY_DIR}"
DOC "Path to lit tool"
)
set(LIT_ARGS
"-v;-s"
CACHE
STRING
"Lit arguments"
)
if ((NOT LIT_TOOL) OR (NOT EXISTS "${LIT_TOOL}"))
message(FATAL_ERROR "The lit tool is required for testing.")
else()
message(STATUS "Using lit: ${LIT_TOOL}")
endif()
endif()
################################################################################
# Utilities
################################################################################
set(GTEST_SRC_DIR "${CMAKE_SOURCE_DIR}/utils/googletest/googletest")
add_subdirectory(utils)
################################################################################
# Runtime
################################################################################
add_subdirectory(runtime)
# Sanity checks
if ("${JFS_LLVM_CLANG_CXX_TOOL}" STREQUAL "")
message(FATAL_ERROR "JFS_LLVM_CLANG_CXX_TOOL not set")
endif()
if (NOT (EXISTS "${JFS_LLVM_CLANG_CXX_TOOL}"))
message(FATAL_ERROR "JFS_LLVM_CLANG_CXX_TOOL (\"${JFS_LLVM_CLANG_CXX_TOOL}\") doest not exist")
endif()
message(STATUS "JFS_LLVM_CLANG_CXX_TOOL: ${JFS_LLVM_CLANG_CXX_TOOL}")
################################################################################
# Libraries
################################################################################
include("${CMAKE_SOURCE_DIR}/cmake/jfs_add_component.cmake")
add_subdirectory(lib)
################################################################################
# Tools
################################################################################
add_subdirectory(tools)
################################################################################
# Tests
################################################################################
add_subdirectory(tests)
================================================
FILE: LICENSE.txt
================================================
Copyright 2017 Daniel Liew
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: README.md
================================================
# JFS
JFS (Just Fuzz it Solver) (originally JIT Fuzzing Solver) is an experimental
constraint solver designed to investigate using __coverage guided fuzzing__ as
an incomplete strategy for solving boolean, BitVector, and floating-point
constraints.
JFS supports constraints in the [SMT-LIBv2][1] constraint langauge in the
`QF_BV`, `QF_BVFP`, and `QF_FP` logics. JFS's primary purpose however is
solve floating-point constraints.
JFS is built on top of the following projects
* [LLVM](https://llvm.org/)
* [Clang](http://clang.llvm.org/)
* [Z3](https://github.com/Z3Prover/z3)
* [LibFuzzer](https://llvm.org/docs/LibFuzzer.html)
[1]: http://smtlib.cs.uiowa.edu/
## FSE 2019 paper
[A paper on JFS](https://srg.doc.ic.ac.uk/files/papers/jfs-esecfse-19.pdf) was presented and published at ESEC/FSE 2019.
Additional resources:
* [artifact](https://github.com/mc-imperial/jfs-fse-2019-artifact)
* [slides](https://docs.google.com/presentation/d/1wPxNJ3rXVqLRCm9jRMZTsL5sEW5aW9WZ583TPpb2Ffo/edit?usp=sharing)
The [Docker image](https://cloud.docker.com/u/delcypher/repository/docker/delcypher/jfs_build) with the tag `fse_2019`
## Using JFS Docker image
If you want to get started with JFS with minimal effort the easiest thing to do
is download the latest Docker image for JFS. Note this image may not be up-to-date
so you might not the latest changes.
To obtain the image run (replace `fse_2019` with the tag you wish to use).
```
docker pull delcypher/jfs_build:fse_2019
```
The simplest invocation is something like this which will show JFS's help output.
```
docker run --user 1000 --rm -t delcypher/jfs_build:fse_2019 /home/user/jfs/build/bin/jfs --help
```
To run JFS on a SMT-LIBv2 file that exists outside the container (`/path/to/simple.smt2` in this example) run this command below.
```
docker run --rm -t -v /path/to/simple.smt2:/tmp/simple.smt2 delcypher/jfs_build:fse_2019 /home/user/jfs/build/bin/jfs /tmp/simple.smt2
```
Note that the `docker run` command creates a new container and destroys it
afterwards which has notable overhead. For better performance consider running
JFS outside of a docker container or creating a single container and spawning a
shell inside it and then launch JFS from there.
## Building JFS
JFS has been tested on Linux and macOS.
Windows support would likely require a lot more work and is dependent on getting
LibFuzzer to work on Windows.
### Using Docker (the easy way)
The easiest way is just to use our Dockerfile. To do this simply run
```
scripts/Dockerfiles/build.sh
```
once the script completes you will have a Docker image on your system
named `jfs_build:ubuntu1604`. In this image you will find the JFS binaries
in the `/home/user/jfs/build/bin` directory.
## From source (the hard way)
JFS has the following build dependencies:
* LLVM/Clang/compiler-rt 6.0
* Z3 4.6.0
* CMake
* Ninja
Here are the steps to build JFS.
1. Build Z3 4.6.0. Note you must build this using Z3's CMake build system
and not its legacy build system because JFS's build system depends on files
emitted by Z3's CMake build system.
A convenience script is provided for this
```bash
export Z3_SRC_DIR=/home/user/z3/src
export Z3_BUILD_DIR=/home/user/z3/build
export Z3_BUILD_TYPE=Release
scripts/dist/build_z3.sh
```
Set the `Z3_SRC_DIR`, `Z3_BUILD_DIR` to paths to empty or non-existant
directories. The `Z3_BUILD_TYPE` can be set to `Release`, `RelWithDebInfo`,
or `Debug`.
2. Build or install LLVM, Clang, and compiler-rt 6.0
A convenience script is provided to build LLVM.
```bash
export LLVM_SRC_DIR=/home/user/llvm/src
export LLVM_BUILD_DIR=/home/user/llvm/src
export LLVM_BUILD_TYPE=Release
scripts/dist/build_llvm.sh
```
Set the `LLVM_SRC_DIR`, `LLVM_BUILD_DIR` to paths to empty or non-existant
directories. The `LLVM_BUILD_TYPE` can be set to `Release`, `RelWithDebInfo`,
or `Debug`.
3. Build JFS
A convenience script is provided to build JFS.
```bash
export JFS_SRC_DIR=/home/user/jfs/src
export JFS_BUILD_DIR=/home/user/jfs/build
export JFS_BUILD_TYPE=Release
scripts/dist/build_jfs.sh
```
`JFS_SRC_DIR` should be the absolute path to an already cloned copy of the JFS
repo. `JFS_BUILD_DIR` should be a path to an empty or non-existant directory.
The `JFS_BUILD_TYPE` can be set to `Release`, `RelWithDebInfo`, or `Debug`.
Note that `Z3_BUILD_DIR` and `LLVM_BUILD_DIR` must also be set.
4. Test JFS
```
cd ${JFS_BUILD_DIR}
ninja check
```
## FAQs
### Aren't there already a bunch of search based floating-point constraint solvers?
Yes. However as far as we're aware, JFS is the first to try to use an
"off the shelf" coverage guided fuzzer as a search strategy.
Here's a non-exhaustive list:
* [coral][2] is a constraint solver that
supports various search strategies over floating point constraints. It uses
its own constraint language which is only partially overlaps with `QF_FP`
constraints in the SMT-LIBv2 language. The [smt2coral][3] tool provides a way
to run coral on SMT-LIBv2 constraints.
* [XSat][4] transform constraints into a mathematical global optimization
problem. Unfortunately this tool is not open source.
* [goSAT][5] takes the ideas behind XSat but
uses different optimization libraries and uses LLVM's JIT to generate code.
We are currently in the process of performing an evaluation of JFS against
these solvers and we will report these results in the not to distant future.
[2]: http://pan.cin.ufpe.br/coral/index.html
[3]: https://github.com/delcypher/smt2coral
[4]: https://www.researchgate.net/publication/305252908_XSat_A_Fast_Floating-Point_Satisfiability_Solver
[5]: https://github.com/abenkhadra/gosat
### How does JFS work?
To see how JFS works let's walk through a small example.
1. Parse SMT-LIB constraints using Z3.
```
(declare-fun a () (_ FloatingPoint 11 53))
(declare-fun b () (_ FloatingPoint 11 53))
(define-fun a_b_rne () (_ FloatingPoint 11 53) (fp.div RNE a b))
(define-fun a_b_rtp () (_ FloatingPoint 11 53) (fp.div RTP a b))
(assert (not (fp.isNaN a)))
(assert (not (fp.isNaN b)))
(assert (not (fp.eq a_b_rne a_b_rtp)))
(assert (not (fp.isNaN a_b_rne)))
(assert (not (fp.isNaN a_b_rtp)))
(check-sat)
```
2. Perform some simplifications on the constraints (e.g. constant folding).
**NOTE: You can use the jfs-opt tool to experiment with these simplifications.**
3. Generate a C++ program where the reachability of an `abort()` statement is
equivalent to finding a satisfying assignment to the constraints.
**NOTE: You can use the `jfs-smt2cxx` tool to convert SMT-LIBv2 constraints
into a program.**
```c++
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
if (size < 16) {
return 0;
}
BufferRef jfs_buffer_ref =
BufferRef(data, size);
const Float<11, 53> a = makeFloatFrom<11, 53>(jfs_buffer_ref, 0, 63);
const Float<11, 53> b = makeFloatFrom<11, 53>(jfs_buffer_ref, 64, 127);
const bool jfs_ssa_0 = a.isNaN();
const bool jfs_ssa_1 = !(jfs_ssa_0);
if (jfs_ssa_1) {
} else {
return 0;
}
const bool jfs_ssa_2 = b.isNaN();
const bool jfs_ssa_3 = !(jfs_ssa_2);
if (jfs_ssa_3) {
} else {
return 0;
}
const Float<11, 53> jfs_ssa_4 = a.div(JFS_RM_RNE, b);
const Float<11, 53> jfs_ssa_5 = a.div(JFS_RM_RTP, b);
const bool jfs_ssa_6 = jfs_ssa_4.ieeeEquals(jfs_ssa_5);
const bool jfs_ssa_7 = !(jfs_ssa_6);
if (jfs_ssa_7) {
} else {
return 0;
}
const bool jfs_ssa_8 = jfs_ssa_4.isNaN();
const bool jfs_ssa_9 = !(jfs_ssa_8);
if (jfs_ssa_9) {
} else {
return 0;
}
const bool jfs_ssa_10 = jfs_ssa_5.isNaN();
const bool jfs_ssa_11 = !(jfs_ssa_10);
if (jfs_ssa_11) {
} else {
return 0;
}
// Fuzzing target
abort();
}
```
4. This program is then compiled by Clang with coverage instrumentation
and linked against LibFuzzer and a small runtime library. The runtime
library implements the `Float` and `BitVector` SMT-LIBv2 types.
5. A set of seeds are generated for the fuzzer.
6. The compiled binary is invoked with the given seeds.
If the fuzzer generates an input that reaches the `abort()` a satisfying
assignment has been found and JFS terminates reporting `sat`.
Note this strategy will never find a satisfying assignment if one does not exist
(i.e. the constraints are unsatisfiable). This is why we say JFS is "incomplete"
because it cannot show that unsatisfiable constraints are unsatisfiable.
There is one exception to this. JFS can show unsatisfiable constraints to be
unsatisfiable if its simplications show one or more constraints to be `false`
(i.e. trivially unsatisfiable).
================================================
FILE: cmake/add_jfs_unit_test.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
if (NOT DEFINED GTEST_SRC_DIR)
message(FATAL_ERROR "GTEST_SRC_DIR must be defined")
endif()
if (NOT EXISTS "${GTEST_SRC_DIR}")
message(FATAL_ERROR "GTEST_SRC_DIR (${GTEST_SRC_DIR}) must exist")
endif()
# This keeps track of all the unit test
# targets so we can ensure they are built
# before trying to run them.
define_property(GLOBAL
PROPERTY JFS_UNIT_TEST_TARGETS
BRIEF_DOCS "JFS unit tests"
FULL_DOCS "JFS unit tests"
)
set(GTEST_INCLUDE_DIR "${GTEST_SRC_DIR}/include")
if (NOT IS_DIRECTORY "${GTEST_INCLUDE_DIR}")
message(FATAL_ERROR
"Cannot find GTest include directory \"${GTEST_INCLUDE_DIR}\"")
endif()
set (UNIT_TEST_EXE_SUFFIX "Test")
function(add_jfs_unit_test target_name)
add_executable(${target_name}${UNIT_TEST_EXE_SUFFIX} ${ARGN})
target_link_libraries(${target_name}${UNIT_TEST_EXE_SUFFIX} PRIVATE jfs_gtest_main)
target_include_directories(${target_name}${UNIT_TEST_EXE_SUFFIX} BEFORE PRIVATE "${GTEST_INCLUDE_DIR}")
set_target_properties(${target_name}${UNIT_TEST_EXE_SUFFIX}
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}"
)
set_property(GLOBAL
APPEND
PROPERTY JFS_UNIT_TEST_TARGETS
${target_name}${UNIT_TEST_EXE_SUFFIX}
)
endfunction()
================================================
FILE: cmake/c_flags_override.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
#
# This file overrides the default compiler flags for CMake's built-in
# configurations (CMAKE_BUILD_TYPE). Most compiler flags should not be set
# here. The main purpose is to make sure ``-DNDEBUG`` is never set by default.
#
#===------------------------------------------------------------------------===#
if (("${CMAKE_C_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_C_COMPILER_ID}" MATCHES "GNU"))
# Taken from Modules/Compiler/GNU.cmake but -DNDEBUG is removed
set(CMAKE_C_FLAGS_INIT "")
set(CMAKE_C_FLAGS_DEBUG_INIT "-O0 -g")
set(CMAKE_C_FLAGS_MINSIZEREL_INIT "-Os")
set(CMAKE_C_FLAGS_RELEASE_INIT "-O3")
set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")
else()
message(FATAL_ERROR "Overrides not set for compiler ${CMAKE_C_COMPILER_ID}")
endif()
================================================
FILE: cmake/compiler_warnings.cmake
================================================
set(GCC_AND_CLANG_WARNINGS
"-Wall"
)
set(GCC_ONLY_WARNINGS "")
set(CLANG_ONLY_WARNINGS "")
set(MSVC_WARNINGS "/W3")
set(WARNING_FLAGS_TO_CHECK "")
if ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU")
list(APPEND WARNING_FLAGS_TO_CHECK ${GCC_AND_CLANG_WARNINGS})
list(APPEND WARNING_FLAGS_TO_CHECK ${GCC_ONLY_WARNINGS})
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang")
list(APPEND WARNING_FLAGS_TO_CHECK ${GCC_AND_CLANG_WARNINGS})
list(APPEND WARNING_FLAGS_TO_CHECK ${CLANG_ONLY_WARNINGS})
# FIXME: Remove "x.." when CMP0054 is set to NEW
elseif ("x${CMAKE_CXX_COMPILER_ID}" STREQUAL "xMSVC")
list(APPEND WARNING_FLAGS_TO_CHECK ${MSVC_WARNINGS})
# CMake's default flags include /W3 already so remove them if
# they already exist.
if ("${CMAKE_CXX_FLAGS}" MATCHES "/W3")
string(REPLACE "/W3" "" _cmake_cxx_flags_remove_w3 "${CMAKE_CXX_FLAGS}")
set(CMAKE_CXX_FLAGS "${_cmake_cxx_flags_remove_w3}" CACHE STRING "" FORCE)
endif()
else()
message(AUTHOR_WARNING "Unknown compiler")
endif()
# Loop through flags and use the ones which the compiler supports
foreach (flag ${WARNING_FLAGS_TO_CHECK})
jfs_component_add_cxx_flag("${flag}")
endforeach()
================================================
FILE: cmake/cxx_flags_override.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
#
# This file overrides the default compiler flags for CMake's built-in
# configurations (CMAKE_BUILD_TYPE). Most compiler flags should not be set
# here. The main purpose is to make sure ``-DNDEBUG`` is never set by default.
#
#===------------------------------------------------------------------------===#
if (("${CMAKE_CXX_COMPILER_ID}" MATCHES "Clang") OR ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU"))
# Taken from Modules/Compiler/GNU.cmake but -DNDEBUG is removed
set(CMAKE_CXX_FLAGS_INIT "")
set(CMAKE_CXX_FLAGS_DEBUG_INIT "-O0 -g")
set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT "-Os")
set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O3")
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "-O2 -g")
else()
message(FATAL_ERROR "Overrides not set for compiler ${CMAKE_CXX_COMPILER_ID}")
endif()
================================================
FILE: cmake/git_utils.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
# add_git_dir_dependency(GIT_DIR SUCCESS_VAR)
#
# Adds a configure time dependency on the git directory such that if the HEAD
# of the git directory changes CMake will be forced to re-run. This useful
# for fetching the current git hash and including it in the build.
#
# `GIT_DIR` is the path to the git directory (i.e. the `.git` directory)
# `SUCCESS_VAR` is the name of the variable to set. It will be set to TRUE
# if the dependency was successfully added and FALSE otherwise.
function(add_git_dir_dependency GIT_DIR SUCCESS_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number (${ARGC}) of arguments")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not an absolute path")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "GIT_DIR (\"${GIT_DIR}\") is not a directory")
endif()
set(GIT_HEAD_FILE "${GIT_DIR}/HEAD")
if (NOT EXISTS "${GIT_HEAD_FILE}")
message(AUTHOR_WARNING "Git head file \"${GIT_HEAD_FILE}\" cannot be found")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
# List of files in the git tree that CMake configuration should depend on
set(GIT_FILE_DEPS "${GIT_HEAD_FILE}")
# Examine the HEAD and workout what additional dependencies there are.
file(READ "${GIT_HEAD_FILE}" GIT_HEAD_DATA LIMIT 128)
string(STRIP "${GIT_HEAD_DATA}" GIT_HEAD_DATA_STRIPPED)
if ("${GIT_HEAD_DATA_STRIPPED}" MATCHES "^ref:[ ]*(.+)$")
# HEAD points at a reference.
set(GIT_REF "${CMAKE_MATCH_1}")
if (EXISTS "${GIT_DIR}/${GIT_REF}")
# Unpacked reference. The file contains the commit hash
# so add a dependency on this file so that if we stay on this
# reference (i.e. branch) but change commit CMake will be forced
# to reconfigure.
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/${GIT_REF}")
elseif(EXISTS "${GIT_DIR}/packed-refs")
# The ref must be packed (see `man git-pack-refs`).
list(APPEND GIT_FILE_DEPS "${GIT_DIR}/packed-refs")
else()
# Fail
message(AUTHOR_WARNING "Unhandled git reference")
set(${SUCCESS_VAR} FALSE PARENT_SCOPE)
return()
endif()
else()
# Detached HEAD.
# No other dependencies needed
endif()
# FIXME:
# This is the directory we will copy (via `configure_file()`) git files
# into. This is a hack. It would be better to use the
# `CMAKE_CONFIGURE_DEPENDS` directory property but that feature is not
# available in CMake 2.8.12. So we use `configure_file()` to effectively
# do the same thing. When the source file to `configure_file()` changes
# it will trigger a re-run of CMake.
set(GIT_CMAKE_FILES_DIR "${CMAKE_CURRENT_BINARY_DIR}/git_cmake_files")
file(MAKE_DIRECTORY "${GIT_CMAKE_FILES_DIR}")
foreach (git_dependency ${GIT_FILE_DEPS})
message(STATUS "Adding git dependency \"${git_dependency}\"")
configure_file(
"${git_dependency}"
"${GIT_CMAKE_FILES_DIR}"
COPYONLY
)
endforeach()
set(${SUCCESS_VAR} TRUE PARENT_SCOPE)
endfunction()
# get_git_head_hash(GIT_DIR OUTPUT_VAR)
#
# Retrieve the current commit hash for a git working directory where `GIT_DIR`
# is the `.git` directory in the root of the git working directory.
#
# `OUTPUT_VAR` should be the name of the variable to put the result in. If this
# function fails then either a fatal error will be raised or `OUTPUT_VAR` will
# contain a string with the suffix `NOTFOUND` which can be used in CMake `if()`
# commands.
function(get_git_head_hash GIT_DIR OUTPUT_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "\"${GIT_DIR}\" is not a directory")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path")
endif()
find_package(Git)
if (NOT Git_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"rev-parse"
"-q" # Quiet
"HEAD"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_HASH
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_HASH}" PARENT_SCOPE)
endfunction()
# get_git_head_describe(GIT_DIR OUTPUT_VAR)
#
# Retrieve the output of `git describe` for a git working directory where
# `GIT_DIR` is the `.git` directory in the root of the git working directory.
#
# `OUTPUT_VAR` should be the name of the variable to put the result in. If this
# function fails then either a fatal error will be raised or `OUTPUT_VAR` will
# contain a string with the suffix `NOTFOUND` which can be used in CMake `if()`
# commands.
function(get_git_head_describe GIT_DIR OUTPUT_VAR)
if (NOT "${ARGC}" EQUAL 2)
message(FATAL_ERROR "Invalid number of arguments")
endif()
if (NOT IS_DIRECTORY "${GIT_DIR}")
message(FATAL_ERROR "\"${GIT_DIR}\" is not a directory")
endif()
if (NOT IS_ABSOLUTE "${GIT_DIR}")
message(FATAL_ERROR \""${GIT_DIR}\" is not an absolute path")
endif()
find_package(Git)
if (NOT Git_FOUND)
set(${OUTPUT_VAR} "GIT-NOTFOUND" PARENT_SCOPE)
return()
endif()
get_filename_component(GIT_WORKING_DIR "${GIT_DIR}" DIRECTORY)
execute_process(
COMMAND
"${GIT_EXECUTABLE}"
"describe"
"--long"
WORKING_DIRECTORY
"${GIT_WORKING_DIR}"
RESULT_VARIABLE
GIT_EXIT_CODE
OUTPUT_VARIABLE
Z3_GIT_DESCRIPTION
OUTPUT_STRIP_TRAILING_WHITESPACE
)
if (NOT "${GIT_EXIT_CODE}" EQUAL 0)
message(WARNING "Failed to execute git")
set(${OUTPUT_VAR} NOTFOUND PARENT_SCOPE)
return()
endif()
set(${OUTPUT_VAR} "${Z3_GIT_DESCRIPTION}" PARENT_SCOPE)
endfunction()
================================================
FILE: cmake/jfs_add_component.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
function(jfs_add_component target_name)
# Components are explicitly STATIC because we don't support building them
# as shared libraries.
add_library(${target_name} STATIC ${ARGN})
# Use of `PUBLIC` means these will propagate to targets that use this component.
if (("${CMAKE_VERSION}" VERSION_EQUAL "3.3") OR ("${CMAKE_VERSION}" VERSION_GREATER "3.3"))
# In newer CMakes we can make sure that the flags are only used when compiling C++
target_compile_options(${target_name} PUBLIC
$<$:${JFS_COMPONENT_CXX_FLAGS}>)
else()
# For older CMakes just live with the warnings we get for passing C++ only flags
# to the C compiler.
target_compile_options(${target_name} PUBLIC ${JFS_COMPONENT_CXX_FLAGS})
endif()
target_include_directories(${target_name} PUBLIC ${JFS_COMPONENT_EXTRA_INCLUDE_DIRS})
target_compile_definitions(${target_name} PUBLIC ${JFS_COMPONENT_CXX_DEFINES})
target_link_libraries(${target_name} PUBLIC ${JFS_COMPONENT_EXTRA_LIBRARIES})
endfunction()
================================================
FILE: cmake/jfs_component_add_cxx_flag.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
include(CheckCXXCompilerFlag)
include(CMakeParseArguments)
function(jfs_component_add_cxx_flag flag)
CMAKE_PARSE_ARGUMENTS(jfs_component_add_cxx_flag "REQUIRED" "" "" ${ARGN})
string(REPLACE "-" "_" SANITIZED_FLAG_NAME "${flag}")
string(REPLACE "/" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE "=" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE " " "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
string(REPLACE "+" "_" SANITIZED_FLAG_NAME "${SANITIZED_FLAG_NAME}")
unset(HAS_${SANITIZED_FLAG_NAME})
CHECK_CXX_COMPILER_FLAG("${flag}" HAS_${SANITIZED_FLAG_NAME})
if (jfs_component_add_cxx_flag_REQUIRED AND NOT HAS_${SANITIZED_FLAG_NAME})
message(FATAL_ERROR "The flag \"${flag}\" is required but your C++ compiler doesn't support it")
endif()
if (HAS_${SANITIZED_FLAG_NAME})
message(STATUS "C++ compiler supports ${flag}")
list(APPEND JFS_COMPONENT_CXX_FLAGS "${flag}")
set(JFS_COMPONENT_CXX_FLAGS ${JFS_COMPONENT_CXX_FLAGS} PARENT_SCOPE)
else()
message(STATUS "C++ compiler does not support ${flag}")
endif()
endfunction()
================================================
FILE: cmake/jfs_external_project_utils.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
function(jfs_get_external_project_build_command OUTPUT_VAR BUILD_DIR)
if ("${CMAKE_GENERATOR}" STREQUAL "Unix Makefiles")
# HACK: This hack means that if the build generator for JFS
# is Make then `-j` value will passed through to make run
# to build the external project.
# See
# http://cmake.3232098.n2.nabble.com/How-would-I-use-parallel-make-on-ExternalProjects-td5609078.html
#
set(JFS_EXTERNAL_PROJECT_BUILD_COMMAND "BUILD_COMMAND" "$(MAKE)")
else()
include(ProcessorCount)
ProcessorCount(NUM_CPUS)
message(STATUS "Detected ${NUM_CPUS} CPUS. Will run this many jobs when building runtime tests")
set(JFS_EXTERNAL_PROJECT_BUILD_COMMAND
"BUILD_COMMAND" "${CMAKE_COMMAND}" "--build" "${BUILD_DIR}" "--" "-j${NUM_CPUS}")
endif()
set(${OUTPUT_VAR} ${JFS_EXTERNAL_PROJECT_BUILD_COMMAND} PARENT_SCOPE)
endfunction()
================================================
FILE: cmake/jfs_get_llvm_components.cmake
================================================
#===------------------------------------------------------------------------===#
#
# JFS
#
# Copyright 2017-2018 Daniel Liew
#
# This file is distributed under the MIT license.
# See LICENSE.txt for details.
#
#===------------------------------------------------------------------------===#
function(jfs_get_llvm_components DESTVAR)
if (${ARGC} LESS 2)
message(FATAL_ERROR "Insufficent number of argument")
endif()
llvm_map_components_to_libnames(llvm_components ${ARGN})
set(${DESTVAR} ${llvm_components} PARENT_SCOPE)
endfunction()
================================================
FILE: docs/tutorial/0-basics-example.smt2
================================================
(declare-fun a () (_ FloatingPoint 11 53))
(declare-fun b () (_ FloatingPoint 11 53))
(define-fun a_b_rne () (_ FloatingPoint 11 53) (fp.div RNE a b))
(define-fun a_b_rtp () (_ FloatingPoint 11 53) (fp.div RTP a b))
(assert (not (fp.isNaN a)))
(assert (not (fp.isNaN b)))
(assert (not (fp.eq a_b_rne a_b_rtp)))
(assert (not (fp.isNaN a_b_rne)))
(assert (not (fp.isNaN a_b_rtp)))
(check-sat)
================================================
FILE: docs/tutorial/0-basics.md
================================================
# JFS basics
This tutorial will walk you through the basics of using JFS.
JFS is designed to solve constraints in the [SMT-LIBv2.6 format](http://smtlib.cs.uiowa.edu/).
More specifically it is designed to solve constraints that
use any combination of Booleans, BitVectors, and floating-point
types.
Let's walk through running JFS on the constraints in the [0-basics-example.smt2](0-basics-example.smt2) file.
Try running the following. **NOTE the $ symbol indicates a shell
prompt and it should not be typed.**
```
$ jfs 0-basics-example.smt2
sat
```
We can see that the tool responded with `sat` meaning that JFS found
a satisfying assignment to the constraints in `0-basics-example.smt2`.
## Verbose output
How do we see what happened? We can use the `-v=1` to see more information. The `-v` sets the verbosity level.
```
$ jfs -v=1 -keep-output-dir 0-basics-example.smt2
(WorkingDirectoryManager "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2", deleteOnDestruction: 1)
pathToBinary: "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/bin/clang++"
pathToRuntimeIncludeDir: "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/include"
pathToLibFuzzerLib: "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/LibFuzzer_RelWithDebInfo/Fuzzer/libLLVMFuzzer.a"
optimizationLevel: O0
debug symbols:false
useASan: false
useUBSan: false
sanitizerCoverageOptions: TRACE_PC_GUARD
(Parser starting)
(Parser finished)
(QueryPassManager starting)
(QueryPassManager "AndHoisting")
(QueryPassManager "Simplification")
(QueryPassManager "AndHoisting")
(QueryPassManager "Simplification")
(QueryPassManager "ConstantPropagation")
(QueryPassManager "AndHoisting")
(QueryPassManager "Simplification")
(QueryPassManager "ConstantPropagation")
(QueryPassManager "Simplification")
(QueryPassManager "AndHoisting")
(QueryPassManager "DuplicateConstraintElimination")
(QueryPassManager "TrueConstraintElimination")
(QueryPassManager "SimpleContradictionsToFalse")
(QueryPassManager "DuplicateConstraintElimination")
(QueryPassManager finished)
(using solver "CXXFuzzingSolver")
(QueryPassManager starting)
(QueryPassManager "EqualityExtractionPass")
(QueryPassManager "FreeVariableToBufferAssignmentPass")
(QueryPassManager finished)
(QueryPassManager starting)
(QueryPassManager "SortConformanceCheckPass")
(QueryPassManager finished)
(QueryPassManager starting)
(QueryPassManager "CXXProgramBuilder")
(QueryPassManager finished)
(ClangInvocationManager
["/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/bin/clang++", "-std=c++11", "-I", "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/include", "-O0", "-fno-omit-frame-pointer", "-fsanitize-coverage=trace-pc-guard", "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/program.cpp", "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/SMTLIB/SMTLIB__DebugSymbols_Optimized_TracePCGuard/libJFSSMTLIBRuntime.a", "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/LibFuzzer_RelWithDebInfo/Fuzzer/libLLVMFuzzer.a", "-o", "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/fuzzer", ]
)
(SeedManager effectiveBound:18446744073709551615)
(SeedManager creating seed "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus/zeros_0")
(SeedManager creating seed "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus/ones_0")
(SeedManager active generators exhausted)
(SeedManager wrote 2 seeds (16 bytes each))
(LibFuzzerInvocationManager
["/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/fuzzer", "-runs=-1", "-seed=1", "-mutate_depth=5", "-cross_over=1", "-max_len=16", "-use_cmp=0", "-print_final_stats=1", "-reduce_inputs=0", "-default_mutators_resize_input=0", "-handle_abrt=1", "-handle_bus=0", "-handle_fpe=0", "-handle_ill=0", "-handle_int=1", "-handle_segv=0", "-handle_term=1", "-handle_xfsz=1", "-artifact_prefix=/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/artifacts/", "-error_exitcode=77", "-timeout_exitcode=88", "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus", ]
)
INFO: Seed: 1
INFO: HACK: Mutators that resize input DISABLED!
INFO: Loaded 1 modules (443 guards): 443 [0x677fd0, 0x6786bc),
INFO: 2 files found in /home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus
JFS WARNING: Wrong sized input tried.
INFO: seed corpus: files: 2 min: 16b max: 16b total: 32b rss: 33Mb
#3 INITED cov: 23 ft: 23 corp: 2/32b exec/s: 0 rss: 33Mb
#6 NEW cov: 24 ft: 26 corp: 3/48b exec/s: 0 rss: 33Mb L: 16/16 MS: 3 CopyPart-CopyPart-ChangeBinInt-
#9 NEW cov: 25 ft: 27 corp: 4/64b exec/s: 0 rss: 33Mb L: 16/16 MS: 3 CrossOver-CopyPart-CrossOver-
==24758== ERROR: libFuzzer: deadly signal
#0 0x42bcd3 in __sanitizer_print_stack_trace /home/user/dev/jfs/llvm6/src/projects/compiler-rt/lib/ubsan/ubsan_diag_standalone.cc:29
#1 0x43e811 in fuzzer::Fuzzer::CrashCallback() /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerLoop.cpp:233:5
#2 0x43e7df in fuzzer::Fuzzer::StaticCrashSignalCallback() /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerLoop.cpp:206:6
#3 0x151b23c44b8f (/usr/lib/libpthread.so.0+0x11b8f)
#4 0x151b23289efa in __GI_raise (/usr/lib/libc.so.6+0x34efa)
#5 0x151b2328b2c0 in __GI_abort (/usr/lib/libc.so.6+0x362c0)
#6 0x42e4a5 in LLVMFuzzerTestOneInput (/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/fuzzer+0x42e4a5)
#7 0x43fa13 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerLoop.cpp:524:13
#8 0x43f2ab in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerLoop.cpp:449:3
#9 0x44043d in fuzzer::Fuzzer::MutateAndTestOne() /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerLoop.cpp:657:19
#10 0x440c75 in fuzzer::Fuzzer::Loop(std::vector, std::allocator >, fuzzer::fuzzer_allocator, std::allocator > > > const&) /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerLoop.cpp:784:5
#11 0x437a6b in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerDriver.cpp:755:6
#12 0x4331a0 in main /home/user/dev/jfs/jfs/src/runtime/LibFuzzer/Fuzzer/FuzzerMain.cpp:20:10
#13 0x151b232769a6 in __libc_start_main (/usr/lib/libc.so.6+0x219a6)
#14 0x406af9 in _start (/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/fuzzer+0x406af9)
NOTE: libFuzzer has rudimentary signal handlers.
Combine libFuzzer with AddressSanitizer or similar for better crash reports.
SUMMARY: libFuzzer: deadly signal
MS: 1 CopyPart-; base unit: 1519e74668a11df04e90de531274a5929990d1fa
0x0,0xff,0xff,0xff,0xff,0xff,0xff,0x0,0x0,0x0,0x0,0x0,0xff,0xff,0xff,0x0,
\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\xff\xff\xff\x00
artifact_prefix='/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/artifacts/'; Test unit written to /home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/artifacts/crash-26f92ccb5076c2b6534271d13d4ac70dc5c26f2f
Base64: AP///////wAAAAAA////AA==
stat::number_of_executed_units: 25
stat::average_exec_per_sec: 0
stat::new_units_added: 2
stat::slowest_unit_time_sec: 0
stat::peak_rss_mb: 38
sat
```
The verbose output shows a lot of internal implementation details of JFS.
We'll now highlight some of the important information.
The line below informs us where JFS's temporary working directory will be
located (note this can be set by using the `-output-dir` option).
Note that `deleteOnDestruction` is set to 1 which means the temporary working
directory will be deleted when JFS exits. To prevent this use the `-keep-output-dir` command line option.
```
(WorkingDirectoryManager "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2", deleteOnDestruction: 1)
```
The following lines indicate that the SMT-LIB parser is running.
```
(Parser starting)
(Parser finished)
```
After parsing the next step is to run a set of simplification passes
on the constraints. We can see this in the `(QueryPassManager ...)` lines.
After this we see the line `(using solver "CXXFuzzingSolver")`. This informs
us that the CXXFuzzingSolver back-end is being used. Note this can be changed
on the command line. See `--help`, e.g. `-z3` causes Z3 to be used to solve the simplified constraints.
After this we see the `QueryPassManager` running again. This is running
some passes that are specific to the CXXFuzzingSolver backend. Notice that
a pass named `CXXProgramBuilder` is executed. This pass reads the constraints
and constructs a C++ program that encodes the constraints as a path
reachability problem.
After this we see the following.
```
(ClangInvocationManager
["/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/bin/clang++", "-std=c++11", "-I", "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/include", "-O0", "-fno-omit-frame-pointer", "-fsanitize-coverage=trace-pc-guard", "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/program.cpp", "/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/SMTLIB/SMTLIB__DebugSymbols_Optimized_TracePCGuard/libJFSSMTLIBRuntime.a",
"/home/user/dev/jfs/jfs/builds/upgrades/gcc_rel/runtime/LibFuzzer_RelWithDebInfo/Fuzzer/libLLVMFuzzer.a", "-o", "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/fuzzer", ]
)
```
This shows us how the Clang compiler is invoked to take the generated C++ programs and generate native code that is linked with [LibFuzzer](https://llvm.org/docs/LibFuzzer.html).
After this we then see the following.
```
(SeedManager effectiveBound:18446744073709551615)
(SeedManager creating seed "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus/zeros_0")
(SeedManager creating seed "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus/ones_0")
(SeedManager active generators exhausted)
(SeedManager wrote 2 seeds (16 bytes each))
```
This is informing us that JFS has created two seeds to fuzz the generated
programs and that each seed is 16 bytes.
After this we see then the following.
```
(LibFuzzerInvocationManager
["/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/fuzzer", "-runs=-1", "-seed=1", "-mutate_depth=5", "-cross_over=1", "-max_len=16", "-use_cmp=0", "-print_final_stats=1", "-reduce_inputs=0", "-default_mutators_resize_input=0", "-handle_abrt=1", "-handle_bus=0", "-handle_fpe=0", "-handle_ill=0", "-handle_int=1", "-handle_segv=0", "-handle_term=1", "-handle_xfsz=1", "-artifact_prefix=/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/artifacts/", "-error_exitcode=77", "-timeout_exitcode=88", "/home/user/dev/jfs/jfs/src/0-basics-example.smt2-2/corpus", ]
)
```
This shows us how the generated binary is invoked to run LibFuzzer.
The output that follows this is [LibFuzzer's output](https://llvm.org/docs/LibFuzzer.html#output). Here we can see that
LibFuzzer catches a deadly signal.
```
==24758== ERROR: libFuzzer: deadly signal
```
Due to the way the generated program is constructed, this indicates that
a satisfying assignment to constraints has been found.
## Working directory
We can run the example again but this time keeping the working directory and
giving it a fixed name.
```
$ jfs -keep-output-dir -output-dir=wd 0-basics-example.smt2
sat
$ cd wd
$ ls
artifacts clang.stderr.txt clang.stdout.txt corpus fuzzer libfuzzer.stderr.txt libfuzzer.stdout.txt program.cpp
```
* `artifacts/` - Contains the input that is a satisfying assignment (if any).
* `clang.stderr.txt` - Contains any standard error output from the Clang invocation.
* `clang.stdout.txt` - Contains any standard output from the Clang invocation.
* `corpus/` - Contains the fuzzing corpus (seeds + found inputs).
* `fuzzer` - Is the fuzzing binary that is executed by JFS
* `libfuzzer.stderr.txt` - Contains any standard output from running the `fuzzer` binary.
* `libfuzzer.stderr.txt` - Contains any standard error output from running the `fuzzer` binary.
* `program.cpp` - The generated C++ program that is compiled using Clang.
Note that the `*.stdout.txt` and `*.stderr.txt` files will not be created
if JFS is used in verbose mode because the output goes to JFS's standard output and standard error output respectively. This behaviour can be changed
by using the `-redirect-clang-output` and `-redirect-libfuzzer-output` options.
================================================
FILE: docs/tutorial/1-setting-resource-limits.md
================================================
# Setting JFS resource limits
TODO
================================================
FILE: docs/tutorial/2-compilation-options-and-runtimes.md
================================================
# Compilation options and runtimes
TODO
================================================
FILE: docs/tutorial/3-resumming-fuzzing.md
================================================
# Resumming fuzzing
TODO
================================================
FILE: docs/tutorial/4-getting-models.md
================================================
# Getting a model from JFS
TODO
================================================
FILE: docs/tutorial/5-jfs-smt2cxx.md
================================================
# The `jfs-smt2cxx` tool
TODO
================================================
FILE: docs/tutorial/6-jfs-opt.md
================================================
# The `jfs-opt` tool
TODO
================================================
FILE: include/jfs/CXXFuzzingBackend/CXXFuzzingSolver.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_FUZZING_SOLVER_H
#define JFS_CXX_FUZZING_BACKEND_FUZZING_SOLVER_H
#include "jfs/FuzzingCommon/FuzzingSolver.h"
namespace jfs {
namespace cxxfb {
class CXXFuzzingSolverImpl;
class CXXFuzzingSolverOptions;
// This solver emits a CXX program and fuzzes it to find a satisfying
// assignment.
class CXXFuzzingSolver : public jfs::fuzzingCommon::FuzzingSolver {
private:
std::unique_ptr impl;
protected:
std::unique_ptr
fuzz(jfs::core::Query& q, bool produceModel,
std::shared_ptr info) override;
public:
CXXFuzzingSolver(
std::unique_ptr options,
std::unique_ptr wdm,
jfs::core::JFSContext& ctx);
~CXXFuzzingSolver();
llvm::StringRef getName() const override;
void cancel() override;
};
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CXXFuzzingSolverOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_FUZZING_SOLVER_OPTIONS_H
#define JFS_CXX_FUZZING_BACKEND_FUZZING_SOLVER_OPTIONS_H
#include "jfs/CXXFuzzingBackend/CXXProgramBuilderOptions.h"
#include "jfs/CXXFuzzingBackend/ClangOptions.h"
#include "jfs/Core/SolverOptions.h"
#include "jfs/FuzzingCommon/FuzzingSolverOptions.h"
#include "jfs/FuzzingCommon/LibFuzzerOptions.h"
#include "jfs/FuzzingCommon/SeedManagerOptions.h"
#include
namespace jfs {
namespace cxxfb {
class CXXFuzzingSolver;
class CXXFuzzingSolverImpl;
class CXXFuzzingSolverOptions
: public jfs::fuzzingCommon::FuzzingSolverOptions {
private:
// Options
std::unique_ptr clangOpt;
std::unique_ptr libFuzzerOpt;
std::unique_ptr cxxProgramBuilderOpt;
std::unique_ptr seedManagerOpt;
public:
CXXFuzzingSolverOptions(
std::unique_ptr<
jfs::fuzzingCommon::FreeVariableToBufferAssignmentPassOptions>
fvtbapOptions,
std::unique_ptr clangOpt,
std::unique_ptr libFuzzerOpt,
std::unique_ptr cxxProgramBuilderOpt,
std::unique_ptr seedManagerOpt,
bool debugSaveModel);
static bool classof(const SolverOptions* so) {
return so->getKind() == CXX_FUZZING_SOLVER_KIND;
}
const ClangOptions* getClangOptions() const { return clangOpt.get(); }
// FIXME: This needs rethinking. This isn't const because the options
// need to be populated with internal implementation details before being
// used.
jfs::fuzzingCommon::LibFuzzerOptions* getLibFuzzerOptions() {
return libFuzzerOpt.get();
}
const CXXProgramBuilderOptions* getCXXProgramBuilderOptions() const {
return cxxProgramBuilderOpt.get();
}
friend class CXXFuzzingSolver;
friend class CXXFuzzingSolverImpl;
// public for convenience.
bool redirectClangOutput;
bool redirectLibFuzzerOutput;
};
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CXXProgram.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CXX_PROGRAM
#define JFS_CXX_FUZZING_BACKEND_CXX_PROGRAM
#include "llvm/Support/raw_ostream.h"
#include
#include
#include
#include
namespace jfs {
namespace cxxfb {
class CXXDecl;
class CXXCodeBlock;
class CXXType;
class CXXFunctionArgument;
class CXXFunctionDecl;
class CXXStatement;
using CXXDeclRef = std::shared_ptr;
using CXXCodeBlockRef = std::shared_ptr;
using CXXTypeRef = std::shared_ptr;
using CXXFunctionArgumentRef = std::shared_ptr;
using CXXStatementRef = std::shared_ptr;
using CXXFunctionDeclRef = std::shared_ptr;
// Base class for all declarations
class CXXDecl {
protected:
// CXXDecl's form a tree with parents owning the children.
// Therefore we don't need to partcipate in ownership (like
// CXXDeclRef would) and raw pointers are fine.
CXXDecl* parent;
public:
CXXDecl(CXXDecl* parent);
virtual ~CXXDecl();
virtual void print(llvm::raw_ostream&) const = 0;
CXXDecl* getParent() const;
void dump() const;
};
// Include
class CXXIncludeDecl : public CXXDecl {
private:
std::string path;
bool isSystemInclude;
public:
CXXIncludeDecl(CXXDecl* parent, llvm::StringRef path, bool systemHeader);
~CXXIncludeDecl() {}
void print(llvm::raw_ostream&) const override;
const std::string& getPath() const { return path; }
};
// Statement (for use inside code blocks)
class CXXStatement : public CXXDecl {
public:
CXXStatement(CXXDecl* parent) : CXXDecl(parent) {}
~CXXStatement();
};
// Comment block
class CXXCommentBlock : public CXXStatement {
private:
std::string comment;
public:
CXXCommentBlock(CXXDecl* parent, llvm::StringRef comment)
: CXXStatement(parent), comment(comment) {}
void print(llvm::raw_ostream&) const override;
const std::string& getComment() const { return comment; }
};
class CXXCodeBlock;
class CXXType;
class CXXFunctionArgument;
// Function definition
class CXXFunctionDecl : public CXXDecl {
private:
std::string name;
CXXTypeRef returnTy;
std::vector arguments;
bool hasCVisibility;
public:
// FIXME: shouldn't be public
CXXCodeBlockRef defn;
// Declaration
CXXFunctionDecl(CXXDecl* parent, llvm::StringRef name, CXXTypeRef returnTy,
std::vector& arguments,
bool hasCVisibility);
// Definition
~CXXFunctionDecl();
void print(llvm::raw_ostream&) const override;
bool isDecl() const { return defn.get() == nullptr; }
bool isDefn() const { return !isDecl(); }
};
// CXXType
class CXXType : public CXXDecl {
private:
std::string name;
bool isConst;
public:
CXXType(CXXDecl* parent, llvm::StringRef name, bool isConst);
CXXType(CXXDecl* parent, llvm::StringRef name);
~CXXType();
void print(llvm::raw_ostream&) const override;
llvm::StringRef getName() const { return name; }
};
// CXXFunctionArgument
class CXXFunctionArgument : public CXXDecl {
private:
std::string name;
CXXTypeRef argType;
public:
CXXFunctionArgument(CXXDecl* parent, llvm::StringRef name,
CXXTypeRef argType);
~CXXFunctionArgument();
void print(llvm::raw_ostream&) const override;
};
// CXXCodeBlock
class CXXCodeBlock : public CXXDecl {
public:
// FIXME: shouldn't be public but its easier to just write to this
std::list statements;
CXXCodeBlock(CXXDecl* parent);
~CXXCodeBlock();
void print(llvm::raw_ostream&) const override;
};
// CXXIfStatement
class CXXIfStatement : public CXXStatement {
private:
std::string condition;
public:
CXXIfStatement(CXXCodeBlock* parent, llvm::StringRef condition);
void print(llvm::raw_ostream&) const override;
// FIXME: shouldn't be public
CXXCodeBlockRef trueBlock;
CXXCodeBlockRef falseBlock;
};
// CXXReturnIntStatement
class CXXReturnIntStatement : public CXXStatement {
private:
int returnValue;
public:
CXXReturnIntStatement(CXXCodeBlock* parent, int returnValue);
void print(llvm::raw_ostream&) const override;
};
// CXXDeclAndDefnVarStatement
class CXXDeclAndDefnVarStatement : public CXXStatement {
private:
CXXTypeRef ty;
std::string name;
std::string valueExpr;
public:
CXXDeclAndDefnVarStatement(CXXDecl* parent, CXXTypeRef ty,
llvm::StringRef name, llvm::StringRef valueExpr);
llvm::StringRef getName() const { return valueExpr; }
void print(llvm::raw_ostream&) const override;
};
// This is a hack
// CXXGenericStatement
class CXXGenericStatement : public CXXStatement {
private:
std::string statement;
public:
CXXGenericStatement(CXXDecl* parent, llvm::StringRef statement);
void print(llvm::raw_ostream&) const override;
};
class CXXProgram : public CXXDecl {
private:
typedef std::vector declStorageTy;
declStorageTy decls;
// FIXME: This should really be a set but we want the order that libraries
// are requested to be preserved.
typedef std::vector libNameStoreageTy;
libNameStoreageTy requiredLibs;
bool recordsRuntimeStats;
public:
CXXProgram() : CXXDecl(nullptr), recordsRuntimeStats(false) {}
void print(llvm::raw_ostream&) const override;
void appendDecl(CXXDeclRef);
void addRequiredLibrary(llvm::StringRef name); // FIXME: Remove unused feature
bool
libraryIsRequired(llvm::StringRef name) const; // FIXME: Remove unused feature
bool getRecordsRuntimeStats() const { return recordsRuntimeStats; }
void setRecordsRuntimeStats(bool v) { recordsRuntimeStats = v; }
// Iterators
declStorageTy::const_iterator cbegin() const { return decls.cbegin(); }
declStorageTy::const_iterator cend() const { return decls.cend(); }
};
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CXXProgramBuilderOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CXX_PROGRAM_BUILDER_OPTIONS_H
#define JFS_CXX_FUZZING_BACKEND_CXX_PROGRAM_BUILDER_OPTIONS_H
#include
namespace jfs {
namespace cxxfb {
class CXXProgramBuilderOptions {
private:
bool recordMaxNumSatisifiedConstraints = false;
bool recordNumberOfInputs = false;
bool recordNumberOfWrongSizedInputs = false;
bool traceIncreaseMaxNumSatisfiedConstraints = false;
bool traceWrongSizedInputs = false;
public:
CXXProgramBuilderOptions();
bool getRecordMaxNumSatisfiedConstraints() const {
return recordMaxNumSatisifiedConstraints;
}
void setRecordMaxNumSatisfiedConstraints(bool v) {
recordMaxNumSatisifiedConstraints = v;
}
bool getRecordNumberOfInputs() const { return recordNumberOfInputs; }
void setRecordNumberOfInputs(bool v) { recordNumberOfInputs = v; }
bool getRecordNumberOfWrongSizedInputs() const {
return recordNumberOfWrongSizedInputs;
}
void setRecordNumberOfWrongSizedInputs(bool v) {
recordNumberOfWrongSizedInputs = v;
}
bool getTraceIncreaseMaxNumSatisfiedConstraints() const {
return traceIncreaseMaxNumSatisfiedConstraints;
}
void setTraceIncreaseMaxNumSatisfiedConstraints(bool v) {
traceIncreaseMaxNumSatisfiedConstraints = v;
}
bool getTraceWrongSizedInputs() const { return traceWrongSizedInputs; }
void setTraceWrongSizedInputs(bool v) { traceWrongSizedInputs = v; }
enum class BranchEncodingTy {
// Fail fast encoding
//
// If a constraint is found to be unsatisfiable fuzzing
// the current input is immediately halted without checking
// the remaining constraints.
//
// There are several problems with this encoding.
//
// * It is sensitive to the order constraints are checked.
// * Potentially prevents partially satisfying inputs from
// being observed which then prevents the input corpus
// from growing.
//
// In essence the encoding forces constraints to be solved
// in particular order.
FAIL_FAST,
// Try all encoding
//
// This is the "Serebryany encoding", named after
// Kostya Serebryany who proposed this.
//
// This encoding evaluates all constraints. This encoding
// addresses problems from the `TRY_ALL` encoding because
// this approach means that the order that constraints are
// checked do not matter.
//
// However it introduces a new problem in that in some cases
// inputs that increase the number of satisfied constraints
// are not added to the input corpus.
//
// For example. Let's say there are three constraints C0, C1, C2, C3.
// Let's say that Input A satisfies {C0, C1} and Input B satisfies {C2}. So
// Inputs A and B get added to the corpus. Then we try Input C which
// satisfies {C0, C1, C2}. This input will not be added to the input corpus
// because the branches for C0, C1, and C2 were already covered.
TRY_ALL,
// Try all IMNCSF
//
// IMNCSF - Increase in Maximum Number of Constraints Solved is a Feature
//
// This is the "Cadar encoding", named after Cristian Cadar
// who proposed this.
//
// This is an enhancement to the `TRY_ALL` encoding that addresses
// the issue where some inputs that increase the number of solved
// constraints
// might not be added to the corpus.
//
// This relies on an experimental LibFuzzer feature to treat an increase in
// the number of solved constraints as a "feature".
//
// At the time of writing this feature on works on Linux.
//
// FIXME: We should guard this so it is only available on Linux.
TRY_ALL_IMNCSF,
};
private:
BranchEncodingTy branchEncoding = BranchEncodingTy::FAIL_FAST;
public:
BranchEncodingTy getBranchEncoding() const { return branchEncoding; }
void setBranchEncoding(BranchEncodingTy ty) { branchEncoding = ty; }
};
} // namespace cxxfb
} // namespace jfs
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CXXProgramBuilderPass.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CXX_PROGRAM_BUILDER_PASS_H
#define JFS_CXX_FUZZING_BACKEND_CXX_PROGRAM_BUILDER_PASS_H
#include "jfs/Core/JFSContext.h"
#include "jfs/FuzzingCommon/FuzzingAnalysisInfo.h"
#include "jfs/Transform/QueryPass.h"
namespace jfs {
namespace cxxfb {
class CXXProgram;
class CXXProgramBuilderPassImpl;
class CXXProgramBuilderOptions;
class CXXProgramBuilderPass : public jfs::transform::QueryPass {
private:
std::unique_ptr impl;
public:
CXXProgramBuilderPass(
std::shared_ptr info,
const CXXProgramBuilderOptions* options, jfs::core::JFSContext& ctx);
~CXXProgramBuilderPass();
bool run(jfs::core::Query& q) override;
virtual llvm::StringRef getName() override;
// FIXME: Should be a const CXXProgram
std::shared_ptr getProgram();
virtual bool convertModel(jfs::core::Model* m) override;
};
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/ClangInvocationManager.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CLANG_INVOCATION_MANAGER_H
#define JFS_CXX_FUZZING_BACKEND_CLANG_INVOCATION_MANAGER_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Support/ICancellable.h"
#include
namespace jfs {
namespace cxxfb {
// Forward declarations
struct ClangOptions;
class ClangInvocationManagerImpl;
class CXXProgram;
class ClangInvocationManager : public jfs::support::ICancellable {
private:
std::unique_ptr impl;
public:
ClangInvocationManager(jfs::core::JFSContext& ctx);
virtual ~ClangInvocationManager();
// Compile `program`. If `sourceFile` is non-empty the source file
// will be written to disk before being read by Clang. If `sourceFile`
// is empty the implementation is allowed to pipe the program directly
// to Clang.
bool compile(const CXXProgram* program, llvm::StringRef sourceFile,
llvm::StringRef outputFile, const ClangOptions* options,
llvm::StringRef stdOutFile, llvm::StringRef stdErrFile);
void cancel() override;
};
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/ClangOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CLANG_OPTIONS_H
#define JFS_CXX_FUZZING_BACKEND_CLANG_OPTIONS_H
#include "jfs/Core/JFSContext.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
#include
#include
namespace jfs {
namespace cxxfb {
struct ClangOptions {
// Paths should be absolute
std::string pathToBinary;
std::string pathToRuntimeDir;
std::string pathToRuntimeIncludeDir;
std::string pathToLibFuzzerLib;
enum class OptimizationLevel { O0, O1, O2, O3 };
OptimizationLevel optimizationLevel;
bool debugSymbols;
bool useASan;
bool useUBSan;
bool useJFSRuntimeAsserts;
enum class SanitizerCoverageTy {
TRACE_PC_GUARD,
TRACE_CMP,
// TODO: Add more
};
std::vector sanitizerCoverageOptions;
// FIXME: We should populate this enum from the CMake
// runtime declarations.
enum class LibFuzzerBuildType {
REL_WITH_DEB_INFO,
};
bool pureRandomFuzzer;
// If `pathToExecutable` is not empty then paths will be
// inferred assuming that `pathToExecutable` is the absolute
// path to the `jfs` binary.
ClangOptions(llvm::StringRef pathToExecutable, LibFuzzerBuildType lfbt,
bool pureRandomFuzzer);
ClangOptions(bool pureRandomFuzzer);
void appendSanitizerCoverageOption(SanitizerCoverageTy opt);
void dump() const;
void print(llvm::raw_ostream& os) const;
bool checkPaths(jfs::core::JFSContext& ctx) const;
};
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CmdLine/CXXProgramBuilderOptionsBuilder.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CMDLINE_CXX_PROGRAM_BUILDER_OPTIONS_BUILDER
#define JFS_CXX_FUZZING_BACKEND_CMDLINE_CXX_PROGRAM_BUILDER_OPTIONS_BUILDER
#include "jfs/CXXFuzzingBackend/CXXProgramBuilderOptions.h"
#include "jfs/Core/JFSContext.h"
#include "llvm/ADT/StringRef.h"
#include
namespace jfs {
namespace cxxfb {
namespace cl {
std::unique_ptr
buildCXXProgramBuilderOptionsFromCmdLine();
}
} // namespace cxxfb
} // namespace jfs
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CmdLine/ClangOptionsBuilder.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CMDLINE_CLANG_OPTIONS_BUILDER_H
#define JFS_CXX_FUZZING_BACKEND_CMDLINE_CLANG_OPTIONS_BUILDER_H
#include "jfs/CXXFuzzingBackend/ClangOptions.h"
#include "jfs/Core/JFSContext.h"
#include "llvm/ADT/StringRef.h"
#include
namespace jfs {
namespace cxxfb {
namespace cl {
std::unique_ptr
buildClangOptionsFromCmdLine(llvm::StringRef pathToExecutable);
}
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/CmdLine/CommandLineCategory.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_CMDLINE_COMMAND_LINE_CATEGORY_H
#define JFS_CXX_FUZZING_BACKEND_CMDLINE_COMMAND_LINE_CATEGORY_H
#include "llvm/Support/CommandLine.h"
namespace jfs {
namespace cxxfb {
namespace cl {
extern llvm::cl::OptionCategory CommandLineCategory;
}
}
}
#endif
================================================
FILE: include/jfs/CXXFuzzingBackend/JFSCXXProgramStat.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CXX_FUZZING_BACKEND_JFS_CXX_PROGRAM_STAT_H
#define JFS_CXX_FUZZING_BACKEND_JFS_CXX_PROGRAM_STAT_H
#endif
#include "jfs/Support/JFSStat.h"
namespace jfs {
namespace cxxfb {
class JFSCXXProgramStat : public jfs::support::JFSStat {
public:
JFSCXXProgramStat(llvm::StringRef name);
virtual ~JFSCXXProgramStat();
void printYAML(llvm::ScopedPrinter& os) const override;
static bool classof(const JFSStat* s) { return s->getKind() == CXX_PROGRAM; }
// FIMXE: Should not be public
uint64_t numConstraints = 0;
uint64_t numEntryFuncStatements = 0;
// FIXME: Doesn't really belong here. The FuzzingAnalysisInfo should have its
// own stat
uint64_t numFreeVars = 0;
uint64_t bufferStoredWidth = 0;
uint64_t bufferTypeWidth = 0; // Sum of the type widths of each BufferElement
uint64_t numEqualitySets = 0;
};
}
}
================================================
FILE: include/jfs/Config/config.h.in
================================================
#ifndef JFS_CONFIG_CONFIG_H
#define JFS_CONFIG_CONFIG_H
// TODO
#endif
================================================
FILE: include/jfs/Config/depsVersion.h.in
================================================
#ifndef JFS_CONFIG_DEPS_VERSION_H
#define JFS_CONFIG_DEPS_VERSION_H
/* LLVM major version number */
#define LLVM_VERSION_MAJOR @LLVM_VERSION_MAJOR@
/* LLVM minor version number */
#define LLVM_VERSION_MINOR @LLVM_VERSION_MINOR@
/* Z3 major version number */
#define Z3_VERSION_MAJOR @Z3_VERSION_MAJOR@
/* Z3 minor version number */
#define Z3_VERSION_MINOR @Z3_VERSION_MINOR@
/* Useful macro to compile code depending on LLVM version */
#define LLVM_VERSION(major, minor) (((major) << 8) | (minor))
#define LLVM_VERSION_CODE LLVM_VERSION(LLVM_VERSION_MAJOR, LLVM_VERSION_MINOR)
#endif
================================================
FILE: include/jfs/Config/version.h.in
================================================
#ifndef JFS_CONFIG_VERSION_H
#define JFS_CONFIG_VERSION_H
/* JFS major version number */
#define JFS_VERSION_MAJOR @JFS_VERSION_MAJOR@
/* JFS minor version number */
#define JFS_VERSION_MINOR @JFS_VERSION_MINOR@
/* JFS patch version number */
#define JFS_VERSION_PATCH @JFS_VERSION_PATCH@
/* JFS tweak version number */
#define JFS_VERSION_TWEAK @JFS_VERSION_TWEAK@
/* JFS git description */
#cmakedefine JFS_GIT_DESCRIPTION @JFS_GIT_DESCRIPTION@
/* JFS git hash */
#cmakedefine JFS_GIT_HASH @JFS_GIT_HASH@
#endif
================================================
FILE: include/jfs/Core/IfVerbose.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_IF_VERBOSE_H
#define JFS_CORE_IF_VERBOSE_H
#define IF_VERB_GT(CTX, VALUE, ACTION) \
do { \
if (CTX.getVerbosity() > VALUE) { \
ACTION; \
} \
} while (0)
#define IF_VERB(CTX, ACTION) IF_VERB_GT(CTX, 0, ACTION)
#endif
================================================
FILE: include/jfs/Core/JFSContext.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_JFSCONTEXT_H
#define JFS_CORE_JFSCONTEXT_H
#include "z3.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/raw_ostream.h"
namespace jfs {
namespace support {
class StatisticsManager;
}
}
namespace jfs {
namespace core {
struct JFSContextConfig {
unsigned verbosity = 0;
bool gathericStatistics = false;
uint64_t seed = 1;
};
class JFSContext;
class JFSContextErrorHandler {
public:
enum ErrorAction { STOP, CONTINUE };
virtual ErrorAction handleZ3error(JFSContext& ctx, Z3_error_code ec) = 0;
virtual ErrorAction handleFatalError(JFSContext& ctx,
llvm::StringRef msg) = 0;
virtual ErrorAction handleGenericError(JFSContext& ctx,
llvm::StringRef msg) = 0;
JFSContextErrorHandler();
virtual ~JFSContextErrorHandler();
};
class JFSContextImpl;
class RNG;
class JFSContext {
private:
const std::unique_ptr impl;
public:
JFSContext(const JFSContextConfig& ctxCfg);
~JFSContext();
// Don't allow copying
JFSContext(const JFSContext&) = delete;
JFSContext(const JFSContext&&) = delete;
JFSContext& operator=(const JFSContext&) = delete;
bool operator==(const JFSContext& other) const;
bool registerErrorHandler(JFSContextErrorHandler* h);
bool unRegisterErrorHandler(JFSContextErrorHandler* h);
Z3_context getZ3Ctx() const;
// TODO: Rethink this API.
unsigned getVerbosity() const;
// Message streams
llvm::raw_ostream& getErrorStream();
llvm::raw_ostream& getWarningStream();
llvm::raw_ostream& getDebugStream();
// FIXME: Should check compiler supports attribute
// Unlike Z3 errors it is guaranteed that execution will
// not leave this function.
__attribute__((noreturn)) void raiseFatalError(llvm::StringRef msg);
void raiseError(llvm::StringRef msg);
jfs::support::StatisticsManager* getStats() const;
const JFSContextConfig& getConfig() const;
RNG& getRNG() const;
};
}
}
#endif // JFS_JFSCONTEXT_H
================================================
FILE: include/jfs/Core/JFSTimerMacros.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_JFS_TIMER_MACROS_H
#define JFS_CORE_JFS_TIMER_MACROS_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Support/JFSStat.h"
#include "jfs/Support/ScopedJFSTimerStatAppender.h"
#include "jfs/Support/StatisticsManager.h"
#define JFS_SM_TIMER(NAME, CTX) \
jfs::support::ScopedJFSTimerStatAppender \
NAME##_timer(((CTX).getConfig().gathericStatistics) ? (CTX.getStats()) \
: nullptr, \
#NAME)
#define JFS_AG_TIMER(DECL_NAME, NAME, AG, CTX) \
jfs::support::ScopedJFSTimerStatAppender< \
jfs::support::JFSAggregateTimerStat> \
DECL_NAME##_timer( \
((CTX).getConfig().gathericStatistics) ? (AG.stats.get()) : nullptr, \
(NAME))
#define JFS_AG_COL(NAME, CTX) \
jfs::support::ScopedJFSAggregateTimerStatAppender< \
jfs::support::StatisticsManager> \
NAME(((CTX).getConfig().gathericStatistics) ? (CTX.getStats()) \
: nullptr, \
#NAME)
#endif
================================================
FILE: include/jfs/Core/Model.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_MODEL_H
#define JFS_CORE_MODEL_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Core/Z3Node.h"
#include
namespace jfs {
namespace core {
struct ModelPrintOptions {
bool sortDecls = false;
bool useModelKeyword = false;
};
class Model {
protected:
jfs::core::Z3ModelHandle z3Model;
JFSContext& ctx;
Model(JFSContext& ctx);
public:
// The idea behind this interface is to allow implementations
// to defer working with Z3ModelHandle and only forcing use when
// `getRepr()` is called. At the time of writing no implementations
// actually do this so perhaps we should remove this complexity?
virtual Z3ASTHandle getAssignmentFor(Z3FuncDeclHandle);
virtual bool addAssignmentFor(Z3FuncDeclHandle decl, Z3ASTHandle e,
bool allowOverwrite = false);
virtual std::string getSMTLIBString(ModelPrintOptions* opts = nullptr);
virtual bool hasAssignmentFor(Z3FuncDeclHandle decl);
virtual Z3ModelHandle getRepr() { return z3Model; }
virtual bool replaceRepr(Z3ModelHandle replacement);
virtual Z3ASTHandle evaluate(Z3ASTHandle e, bool modelCompletion);
JFSContext& getContext();
virtual ~Model();
static Z3ASTHandle getDefaultValueFor(Z3SortHandle sort);
};
} // namespace core
} // namespace jfs
#endif
================================================
FILE: include/jfs/Core/ModelValidator.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Alastair Donaldson
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_MODEL_VALIDATOR_H
#define JFS_CORE_MODEL_VALIDATOR_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Core/Model.h"
#include "jfs/Core/Query.h"
#include "jfs/Core/Z3Node.h"
#include
namespace jfs {
namespace core {
class ValidationFailureInfo {
public:
enum ReasonTy {
NO_REASON,
EVALUATED_TO_FALSE,
EVALUATED_TO_NON_CONSTANT,
EVALUATED_TO_NON_BOOL_SORT,
};
ReasonTy reason;
uint64_t index;
Z3ASTHandle constraint;
Model* model;
// TODO: Add methods to allow further debugging.
// It would be useful to recursively walk the AST
// to find which assignments are responsible and
// which part of the subtree is causing the constraint
// to evaluate to false.
ValidationFailureInfo(ReasonTy reason, uint64_t index, Z3ASTHandle constraint,
Model* model);
ValidationFailureInfo();
static const char* reasonAsString(ReasonTy reason);
};
class ModelValidationOptions {
public:
bool warnOnVariablesMissingAssignment = true;
};
class ModelValidator {
public:
using VFIContainerTy = std::vector;
private:
VFIContainerTy failures;
public:
ModelValidator();
~ModelValidator();
VFIContainerTy::const_iterator cbegin() const { return failures.cbegin(); }
VFIContainerTy::const_iterator cend() const { return failures.cend(); }
VFIContainerTy::iterator begin() { return failures.begin(); }
VFIContainerTy::iterator end() { return failures.end(); }
uint64_t getNumberOfFailures() const { return failures.size(); }
void reset();
bool validate(const Query& q, Model* m,
const ModelValidationOptions* options = nullptr);
std::string toStr() const;
};
} // namespace core
} // namespace jfs
#endif
================================================
FILE: include/jfs/Core/Query.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_QUERY_H
#define JFS_CORE_QUERY_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeSet.h"
#include "llvm/Support/raw_ostream.h"
#include
namespace jfs {
namespace core {
class Query {
private:
JFSContext& ctx;
public:
std::vector constraints;
Query(JFSContext& ctx);
~Query();
Query(const Query& other);
// In principle there's no reason we can't have these deleted methods.
// However we don't need them yet and I don't want the implicit declarations
// to accidently be called.
Query(const Query&&) = delete;
Query& operator=(const Query&) = delete;
Query& operator=(const Query&&) = delete;
void dump() const;
void collectFuncDecls(Z3FuncDeclSet& variables) const;
void print(llvm::raw_ostream& os) const;
JFSContext& getContext() const { return ctx; }
static bool areSame(std::vector& a, std::vector& b,
bool ignoreOrder = false);
};
// Operator overload for easy printing of queries
llvm::raw_ostream& operator<<(llvm::raw_ostream& os, const Query& q);
}
}
#endif
================================================
FILE: include/jfs/Core/RNG.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2018 J. Ryan Stinnett
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_RNG_H
#define JFS_CORE_RNG_H
#include
#include
namespace jfs {
namespace core {
class RNG {
private:
std::mt19937_64 generator;
public:
RNG(uint64_t seed)
: generator(seed ? seed : std::mt19937_64::default_seed) {}
// Produce an integer in the range [0, limit).
uint64_t generate(uint64_t limit);
};
} // jfs
} // core
#endif // JFS_CORE_RNG_H
================================================
FILE: include/jfs/Core/SMTLIB2Parser.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_SMTLIB2PARSER_H
#define JFS_CORE_SMTLIB2PARSER_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Core/Query.h"
#include "llvm/ADT/StringRef.h"
#include
namespace llvm {
class MemoryBuffer;
}
namespace jfs {
namespace core {
class SMTLIB2Parser : public JFSContextErrorHandler {
public:
SMTLIB2Parser(JFSContext& ctx);
~SMTLIB2Parser();
std::shared_ptr parseFile(llvm::StringRef fileName);
std::shared_ptr parseStr(llvm::StringRef str);
std::shared_ptr
parseMemoryBuffer(std::unique_ptr buffer);
ErrorAction handleZ3error(JFSContext& ctx, Z3_error_code ec) override;
ErrorAction handleFatalError(JFSContext& ctx, llvm::StringRef msg) override;
ErrorAction handleGenericError(JFSContext& ctx, llvm::StringRef msg) override;
unsigned getErrorCount() const;
void resetErrorCount();
private:
JFSContext& ctx;
unsigned errorCount;
};
}
}
#endif
================================================
FILE: include/jfs/Core/ScopedJFSContextErrorHandler.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_SCOPED_JFS_CONTEXT_ERROR_HANDLER_H
#define JFS_CORE_SCOPED_JFS_CONTEXT_ERROR_HANDLER_H
#include "jfs/Core/JFSContext.h"
namespace jfs {
namespace core {
class ScopedJFSContextErrorHandler {
private:
JFSContext& ctx;
JFSContextErrorHandler* handler;
public:
ScopedJFSContextErrorHandler(JFSContext& ctx, JFSContextErrorHandler* h)
: ctx(ctx), handler(h) {
ctx.registerErrorHandler(handler);
}
~ScopedJFSContextErrorHandler() { ctx.unRegisterErrorHandler(handler); }
};
}
}
#endif
================================================
FILE: include/jfs/Core/SimpleModel.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Alastair Donaldson
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_SIMPLE_MODEL_H
#define JFS_CORE_SIMPLE_MODEL_H
#include "jfs/Core/Model.h"
namespace jfs {
namespace core {
// A model that on creation is empty
class SimpleModel : public Model {
public:
SimpleModel(JFSContext& ctx);
};
} // namespace core
} // namespace jfs
#endif
================================================
FILE: include/jfs/Core/Solver.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_SOLVER_H
#define JFS_CORE_SOLVER_H
#include "jfs/Core/Query.h"
#include "jfs/Core/SolverOptions.h"
#include "jfs/Support/ICancellable.h"
#include "llvm/ADT/StringRef.h"
#include
#include
namespace jfs {
namespace core {
class Model;
class SolverResponse {
public:
enum SolverSatisfiability { SAT, UNSAT, UNKNOWN };
SolverResponse(SolverSatisfiability sat);
virtual ~SolverResponse();
const SolverSatisfiability sat;
virtual Model* getModel() = 0;
static llvm::StringRef getSatString(SolverSatisfiability);
};
class Solver : public jfs::support::ICancellable {
protected:
std::unique_ptr options;
JFSContext& ctx;
public:
Solver(std::unique_ptr options, JFSContext& ctx);
virtual ~Solver();
Solver(const Solver&) = delete;
Solver(const Solver&&) = delete;
Solver& operator=(const Solver&) = delete;
// Determine the satisfiability of the query.
// Iff `produceModel` is false then only satisfiability will
// be available.
virtual std::unique_ptr solve(const Query& q,
bool produceModel) = 0;
const SolverOptions* getOptions() const;
virtual llvm::StringRef getName() const = 0;
JFSContext& getContext() { return ctx; }
};
}
}
#endif
================================================
FILE: include/jfs/Core/SolverOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_SOLVER_OPTIONS_H
#define JFS_CORE_SOLVER_OPTIONS_H
#include "llvm/Support/Casting.h"
#include
namespace jfs {
namespace core {
class SolverOptions {
// START: LLVM RTTI boilerplate code
public:
// NOTE: When updating this enum make sure you update all implementations
// of `classof(const SolverOptions* so)`.
enum SolverOptionKind {
SOLVER_OPTIONS_KIND,
FUZZING_SOLVER_KIND,
CXX_FUZZING_SOLVER_KIND,
LAST_FUZZING_SOLVER_KIND // This is a dummy entry
};
private:
const SolverOptionKind kind;
protected:
SolverOptions(SolverOptionKind kind) : kind(kind) {}
public:
SolverOptions() : SolverOptions(SOLVER_OPTIONS_KIND) {}
virtual ~SolverOptions() {}
SolverOptionKind getKind() const { return kind; }
static bool classof(const SolverOptions* so) {
return so->getKind() == SOLVER_OPTIONS_KIND;
}
// END: LLVM RTTI boilerplate code
// Options common to all solvers
};
}
}
#endif
================================================
FILE: include/jfs/Core/ToolErrorHandler.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_TOOL_ERROR_HANDLER_H
#define JFS_CORE_TOOL_ERROR_HANDLER_H
#include "jfs/Core/JFSContext.h"
namespace jfs {
namespace core {
class ToolErrorHandler : public JFSContextErrorHandler {
private:
bool ignoreCanceled;
public:
ToolErrorHandler(bool ignoreCanceled) : ignoreCanceled(ignoreCanceled) {}
JFSContextErrorHandler::ErrorAction handleZ3error(JFSContext& ctx,
Z3_error_code ec) override;
ErrorAction handleFatalError(JFSContext& ctx, llvm::StringRef msg) override;
ErrorAction handleGenericError(JFSContext& ctx, llvm::StringRef msg) override;
};
}
}
#endif
================================================
FILE: include/jfs/Core/Z3ASTCmp.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_Z3_AST_CMP
#define JFS_CORE_Z3_AST_CMP
#include "jfs/Core/Z3Node.h"
#include
namespace jfs {
namespace core {
struct Z3ASTHashGet {
size_t operator()(const Z3ASTHandle& h) const {
return ::Z3_get_ast_hash(h.getContext(), h);
}
};
struct Z3ASTCmp {
bool operator()(const Z3ASTHandle& a, const Z3ASTHandle b) const {
assert(a.getContext() == b.getContext() && "Contexts must be equal");
return ::Z3_is_eq_ast(a.getContext(), a, b);
}
};
struct Z3SortHashGet {
size_t operator()(const Z3SortHandle& h) const {
return ::Z3_get_ast_hash(h.getContext(), h.asAST());
}
};
struct Z3SortCmp {
bool operator()(const Z3SortHandle& a, const Z3SortHandle b) const {
assert(a.getContext() == b.getContext() && "Contexts must be equal");
return ::Z3_is_eq_ast(a.getContext(), a.asAST(), b.asAST());
}
};
struct Z3FuncDeclHashGet {
size_t operator()(const Z3FuncDeclHandle& h) const {
return ::Z3_get_ast_hash(h.getContext(),
::Z3_func_decl_to_ast(h.getContext(), h));
}
};
struct Z3FuncDeclCmp {
bool operator()(const Z3FuncDeclHandle& a, const Z3FuncDeclHandle b) const {
assert(a.getContext() == b.getContext() && "Contexts must be equal");
return ::Z3_is_eq_ast(a.getContext(),
::Z3_func_decl_to_ast(a.getContext(), a),
::Z3_func_decl_to_ast(b.getContext(), b));
}
};
}
}
#endif
================================================
FILE: include/jfs/Core/Z3ASTVisitor.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_Z3_AST_VISITOR_H
#define JFS_CORE_Z3_AST_VISITOR_H
#include "jfs/Core/Z3Node.h"
namespace jfs {
namespace core {
// FIXME: This design only works for
// read only traversal. It needs rethinking
// for Z3AST modification and traversal order
class Z3ASTVisitor {
public:
Z3ASTVisitor();
virtual ~Z3ASTVisitor();
void visit(Z3ASTHandle e);
protected:
// TODO: Add more methods for different Z3 application kinds
// Uninterpreted function
virtual void visitUninterpretedFunc(Z3AppHandle e) = 0;
// Constants
virtual void visitBoolConstant(Z3AppHandle e) = 0;
virtual void visitBitVector(Z3AppHandle e) = 0;
virtual void visitFloatingPointConstant(Z3AppHandle e) = 0;
// Overloaded operations
virtual void visitEqual(Z3AppHandle e) = 0;
virtual void visitDistinct(Z3AppHandle e) = 0;
virtual void visitIfThenElse(Z3AppHandle e) = 0;
virtual void visitImplies(Z3AppHandle e) = 0;
// This isn't part of the core SMT-LIBv2 theory. Is this a Z3 extension?
virtual void visitIff(Z3AppHandle e) = 0;
// Boolean operations
virtual void visitAnd(Z3AppHandle e) = 0;
virtual void visitOr(Z3AppHandle e) = 0;
virtual void visitXor(Z3AppHandle e) = 0;
virtual void visitNot(Z3AppHandle e) = 0;
// Arithmetic BitVector operations
virtual void visitBvNeg(Z3AppHandle e) = 0;
virtual void visitBvAdd(Z3AppHandle e) = 0;
virtual void visitBvSub(Z3AppHandle e) = 0;
virtual void visitBvMul(Z3AppHandle e) = 0;
virtual void visitBvSDiv(Z3AppHandle e) = 0;
virtual void visitBvUDiv(Z3AppHandle e) = 0;
virtual void visitBvSRem(Z3AppHandle e) = 0;
virtual void visitBvURem(Z3AppHandle e) = 0;
virtual void visitBvSMod(Z3AppHandle e) = 0;
// Comparison BitVector operations
virtual void visitBvULE(Z3AppHandle e) = 0;
virtual void visitBvSLE(Z3AppHandle e) = 0;
virtual void visitBvUGE(Z3AppHandle e) = 0;
virtual void visitBvSGE(Z3AppHandle e) = 0;
virtual void visitBvULT(Z3AppHandle e) = 0;
virtual void visitBvSLT(Z3AppHandle e) = 0;
virtual void visitBvUGT(Z3AppHandle e) = 0;
virtual void visitBvSGT(Z3AppHandle e) = 0;
virtual void visitBvComp(Z3AppHandle e) = 0;
// Bitwise BitVector operations
virtual void visitBvAnd(Z3AppHandle e) = 0;
virtual void visitBvOr(Z3AppHandle e) = 0;
virtual void visitBvNot(Z3AppHandle e) = 0;
virtual void visitBvXor(Z3AppHandle e) = 0;
virtual void visitBvNand(Z3AppHandle e) = 0;
virtual void visitBvNor(Z3AppHandle e) = 0;
virtual void visitBvXnor(Z3AppHandle e) = 0;
// Shift and rotation BitVector operations
virtual void visitBvShl(Z3AppHandle e) = 0;
virtual void visitBvLShr(Z3AppHandle e) = 0;
virtual void visitBvAShr(Z3AppHandle e) = 0;
virtual void visitBvRotateLeft(Z3AppHandle e) = 0;
virtual void visitBvRotateRight(Z3AppHandle e) = 0;
// Sort changing BitVector operations
virtual void visitBvConcat(Z3AppHandle e) = 0;
virtual void visitBvSignExtend(Z3AppHandle e) = 0;
virtual void visitBvZeroExtend(Z3AppHandle e) = 0;
virtual void visitBvExtract(Z3AppHandle e) = 0;
// Floating point operations
virtual void visitFloatingPointFromTriple(Z3AppHandle e) = 0;
virtual void visitFloatingPointFromIEEEBitVector(Z3AppHandle e) = 0;
virtual void visitFloatIsNaN(Z3AppHandle e) = 0;
virtual void visitFloatIsNormal(Z3AppHandle e) = 0;
virtual void visitFloatIsSubnormal(Z3AppHandle e) = 0;
virtual void visitFloatIsZero(Z3AppHandle e) = 0;
virtual void visitFloatIsPositive(Z3AppHandle e) = 0;
virtual void visitFloatIsNegative(Z3AppHandle e) = 0;
virtual void visitFloatIsInfinite(Z3AppHandle e) = 0;
virtual void visitFloatIEEEEquals(Z3AppHandle e) = 0;
virtual void visitFloatLessThan(Z3AppHandle e) = 0;
virtual void visitFloatLessThanOrEqual(Z3AppHandle e) = 0;
virtual void visitFloatGreaterThan(Z3AppHandle e) = 0;
virtual void visitFloatGreaterThanOrEqual(Z3AppHandle e) = 0;
virtual void visitFloatPositiveZero(Z3AppHandle e) = 0;
virtual void visitFloatNegativeZero(Z3AppHandle e) = 0;
virtual void visitFloatPositiveInfinity(Z3AppHandle e) = 0;
virtual void visitFloatNegativeInfinity(Z3AppHandle e) = 0;
virtual void visitFloatNaN(Z3AppHandle e) = 0;
virtual void visitFloatAbs(Z3AppHandle e) = 0;
virtual void visitFloatNeg(Z3AppHandle e) = 0;
virtual void visitFloatMin(Z3AppHandle e) = 0;
virtual void visitFloatMax(Z3AppHandle e) = 0;
virtual void visitFloatAdd(Z3AppHandle e) = 0;
virtual void visitFloatSub(Z3AppHandle e) = 0;
virtual void visitFloatMul(Z3AppHandle e) = 0;
virtual void visitFloatDiv(Z3AppHandle e) = 0;
virtual void visitFloatFMA(Z3AppHandle e) = 0;
virtual void visitFloatSqrt(Z3AppHandle e) = 0;
virtual void visitFloatRem(Z3AppHandle e) = 0;
virtual void visitFloatRoundToIntegral(Z3AppHandle e) = 0;
virtual void visitConvertToFloatFromFloat(Z3AppHandle e) = 0;
virtual void visitConvertToFloatFromUnsignedBitVector(Z3AppHandle e) = 0;
virtual void visitConvertToFloatFromSignedBitVector(Z3AppHandle e) = 0;
virtual void visitConvertToUnsignedBitVectorFromFloat(Z3AppHandle e) = 0;
virtual void visitConvertToSignedBitVectorFromFloat(Z3AppHandle e) = 0;
};
}
}
#endif
================================================
FILE: include/jfs/Core/Z3Node.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_Z3NODE_H
#define JFS_CORE_Z3NODE_H
#include "z3.h"
#include
#include
#include
namespace jfs {
namespace core {
template class Z3NodeHandle {
// Internally these Z3 types are pointers
// so storing these should be cheap.
// It would be nice if we could infer the Z3_context from the node
// but I can't see a way to do this from Z3's API.
protected:
T node;
::Z3_context context;
private:
// To be specialised
inline void inc_ref(T node);
inline void dec_ref(T node);
public:
Z3NodeHandle() : node(NULL), context(NULL) {}
Z3NodeHandle(const T _node, const ::Z3_context _context)
: node(_node), context(_context) {
if (node && context) {
inc_ref(node);
}
};
~Z3NodeHandle() {
if (node && context) {
dec_ref(node);
}
}
Z3NodeHandle(const Z3NodeHandle& b) : node(b.node), context(b.context) {
if (node && context) {
inc_ref(node);
}
}
Z3NodeHandle& operator=(const Z3NodeHandle& b) {
if (node == NULL && context == NULL) {
// Special case for when this object was constructed
// using the default constructor. Try to inherit a non null
// context.
context = b.context;
}
assert(context == b.context && "Mismatched Z3 contexts!");
// node != nullptr ==> context != NULL
assert((node == NULL || context) &&
"Can't have non nullptr node with nullptr context");
if (node && context) {
dec_ref(node);
}
node = b.node;
if (node && context) {
inc_ref(node);
}
return *this;
}
// To be specialised
void dump() const;
std::string toStr() const;
operator T() const { return node; }
Z3_context getContext() const { return context; }
bool isNull() const { return node == nullptr; }
};
// Instantiate templates
// Specialise for Z3_sort
template <> inline void Z3NodeHandle::inc_ref(Z3_sort node) {
// In Z3 internally this call is just a cast. We could just do that
// instead to simplify our implementation but this seems cleaner.
::Z3_inc_ref(context, ::Z3_sort_to_ast(context, node));
}
template <> inline void Z3NodeHandle::dec_ref(Z3_sort node) {
// In Z3 internally this call is just a cast. We could just do that
// instead to simplify our implementation but this seems cleaner.
::Z3_dec_ref(context, ::Z3_sort_to_ast(context, node));
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
class Z3ASTHandle;
class Z3SortHandle : public Z3NodeHandle {
public:
// Inherit constructors
using Z3NodeHandle::Z3NodeHandle;
// Helper methods
Z3_sort_kind getKind() const;
bool isBoolTy() const;
bool isBitVectorTy() const;
bool isFloatingPointTy() const;
// Return 0 if not bitvector, floating point, or bool
unsigned getWidth() const;
// Return 0 if not a bitvector
unsigned getBitVectorWidth() const;
// Return 0 if not floating point
unsigned getFloatingPointBitWidth() const;
unsigned getFloatingPointExponentBitWidth() const;
unsigned getFloatingPointSignificandBitWidth() const; // Includes implicit bit
Z3ASTHandle asAST() const;
static Z3SortHandle getBoolTy(Z3_context ctx);
static Z3SortHandle getBitVectorTy(Z3_context, unsigned bitWidth);
static Z3SortHandle getFloat32Ty(Z3_context ctx);
static Z3SortHandle getFloat64Ty(Z3_context ctx);
};
// Specialise for Z3_ast
template <> inline void Z3NodeHandle::inc_ref(Z3_ast node) {
::Z3_inc_ref(context, node);
}
template <> inline void Z3NodeHandle::dec_ref(Z3_ast node) {
::Z3_dec_ref(context, node);
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
class Z3AppHandle;
class Z3FuncDeclHandle;
// Provide a class rather than a typedef so we can add
// additional helper methods.
class Z3ASTHandle : public Z3NodeHandle {
public:
// Inherit constructors
using Z3NodeHandle::Z3NodeHandle;
// Helper methods
Z3_ast_kind getKind() const;
bool isApp() const;
bool isFuncDecl() const;
bool isSort() const;
bool isNumeral() const;
bool isTrue() const;
bool isFalse() const;
bool isConstant() const;
// FIXME: Should be renamed isAppOfFreeVariable
bool isFreeVariable() const;
bool isAppOf(Z3_decl_kind) const;
bool isStructurallyEqualTo(Z3ASTHandle other) const;
Z3SortHandle getSort() const;
Z3AppHandle asApp() const;
Z3FuncDeclHandle asFuncDecl() const;
static Z3ASTHandle getTrue(Z3_context ctx);
static Z3ASTHandle getFalse(Z3_context ctx);
static Z3ASTHandle getBVZero(Z3_context, unsigned width);
static Z3ASTHandle getBVZero(Z3SortHandle sort);
static Z3ASTHandle getBV(Z3SortHandle sort, uint64_t value);
static Z3ASTHandle getFloatAbsoluteSmallestSubnormal(Z3SortHandle sort,
bool positive);
static Z3ASTHandle getFloatAbsoluteLargestSubnormal(Z3SortHandle sort,
bool positive);
static Z3ASTHandle getFloatAbsoluteSmallestNormal(Z3SortHandle sort,
bool positive);
static Z3ASTHandle getFloatAbsoluteLargestNormal(Z3SortHandle sort,
bool positive);
static Z3ASTHandle getFloatZero(Z3SortHandle sort, bool positive = true);
static Z3ASTHandle getFloatInfinity(Z3SortHandle sort, bool positive = true);
static Z3ASTHandle getFloatNAN(Z3SortHandle sort);
static Z3ASTHandle getFloatFromInt(Z3SortHandle sort, signed value);
};
// Specialise for Z3_app
template <> inline void Z3NodeHandle::inc_ref(Z3_app node) {
::Z3_inc_ref(context, ::Z3_app_to_ast(context, node));
}
template <> inline void Z3NodeHandle::dec_ref(Z3_app node) {
::Z3_dec_ref(context, ::Z3_app_to_ast(context, node));
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
// FIXME: It's silly that Z3AppHandle does not inherit from Z3ASTHandle
// to reflect the hierarchy in Z3.
// Provide a class rather than a typedef so we can add
// additional helper methods.
class Z3AppHandle : public Z3NodeHandle {
public:
// Inherit constructors
using Z3NodeHandle::Z3NodeHandle;
// Helper methods
Z3FuncDeclHandle getFuncDecl() const;
Z3_decl_kind getKind() const;
unsigned getNumKids() const;
Z3ASTHandle getKid(unsigned) const;
bool isConstant() const;
// FIXME: Should be renamed isAppOfFreeVariable
bool isFreeVariable() const;
bool isSpecialFPConstant() const;
Z3ASTHandle asAST() const;
Z3SortHandle getSort() const;
bool getConstantAsUInt64(uint64_t* out) const;
};
// Specialise for Z3_func_decl
template <> inline void Z3NodeHandle::inc_ref(Z3_func_decl node) {
::Z3_inc_ref(context, ::Z3_func_decl_to_ast(context, node));
}
template <> inline void Z3NodeHandle::dec_ref(Z3_func_decl node) {
::Z3_dec_ref(context, ::Z3_func_decl_to_ast(context, node));
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
// FIXME: It's silly that Z3FuncDeclHandle does not inherit from Z3ASTHandle
// to reflect the hierarchy in Z3.
// Provide a class rather than a typedef so we can add
// additional helper methods.
class Z3FuncDeclHandle : public Z3NodeHandle {
// Inherit constructors
public:
using Z3NodeHandle::Z3NodeHandle;
Z3_decl_kind getKind() const;
Z3SortHandle getSort() const;
std::string getName() const;
Z3ASTHandle asAST() const;
// Parameters
unsigned getNumParams() const;
Z3_parameter_kind getParamKind(unsigned index) const;
int getIntParam(unsigned index) const;
};
// Specialise for Z3_solver
template <> inline void Z3NodeHandle::inc_ref(Z3_solver node) {
::Z3_solver_inc_ref(context, node);
}
template <> inline void Z3NodeHandle::dec_ref(Z3_solver node) {
::Z3_solver_dec_ref(context, node);
}
typedef Z3NodeHandle Z3SolverHandle;
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
// Specialise for Z3_params
template <> inline void Z3NodeHandle::inc_ref(Z3_params node) {
::Z3_params_inc_ref(context, node);
}
template <> inline void Z3NodeHandle::dec_ref(Z3_params node) {
::Z3_params_dec_ref(context, node);
}
typedef Z3NodeHandle Z3ParamsHandle;
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
// Specialise for Z3_model
template <> inline void Z3NodeHandle::inc_ref(Z3_model node) {
::Z3_model_inc_ref(context, node);
}
template <> inline void Z3NodeHandle::dec_ref(Z3_model node) {
::Z3_model_dec_ref(context, node);
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
class Z3ModelHandle : public Z3NodeHandle {
// Inherit constructors
public:
using Z3NodeHandle::Z3NodeHandle;
Z3ASTHandle getAssignmentFor(Z3FuncDeclHandle);
bool hasAssignmentFor(Z3FuncDeclHandle d) const;
bool addAssignmentFor(Z3FuncDeclHandle decl, Z3ASTHandle e,
bool allowOverwrite = false);
uint64_t getNumAssignments() const;
Z3FuncDeclHandle getVariableDeclForIndex(uint64_t index);
Z3ASTHandle evaluate(Z3ASTHandle e, bool modelCompletion);
bool isEmpty() const;
};
// Specialise for Z3_goal
template <> inline void Z3NodeHandle::inc_ref(Z3_goal node) {
::Z3_goal_inc_ref(context, node);
}
template <> inline void Z3NodeHandle::dec_ref(Z3_goal node) {
::Z3_goal_dec_ref(context, node);
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
class Z3GoalHandle : public Z3NodeHandle {
// Inherit constructors
public:
using Z3NodeHandle::Z3NodeHandle;
void addFormula(Z3ASTHandle);
unsigned getNumFormulas() const;
Z3ASTHandle getFormula(unsigned index) const;
};
class Z3ApplyResultHandle;
// Specialise for Z3_tactic
template <> inline void Z3NodeHandle::inc_ref(Z3_tactic node) {
::Z3_tactic_inc_ref(context, node);
}
template <> inline void Z3NodeHandle::dec_ref(Z3_tactic node) {
::Z3_tactic_dec_ref(context, node);
}
template <> void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
class Z3TacticHandle : public Z3NodeHandle {
// Inherit constructors
public:
using Z3NodeHandle::Z3NodeHandle;
Z3ApplyResultHandle apply(Z3GoalHandle goal);
Z3ApplyResultHandle applyWithParams(Z3GoalHandle goal, Z3ParamsHandle params);
};
// Specialise for Z3_apply_result
template <>
inline void Z3NodeHandle::inc_ref(Z3_apply_result node) {
::Z3_apply_result_inc_ref(context, node);
}
template <>
inline void Z3NodeHandle::dec_ref(Z3_apply_result node) {
::Z3_apply_result_dec_ref(context, node);
}
template <>
void Z3NodeHandle::dump() const __attribute__((used));
template <>
std::string Z3NodeHandle::toStr() const __attribute__((used));
class Z3ApplyResultHandle : public Z3NodeHandle {
// Inherit constructors
public:
using Z3NodeHandle::Z3NodeHandle;
unsigned getNumGoals() const;
Z3GoalHandle getGoal(unsigned index) const;
void collectAllFormulas(std::vector&) const;
Z3ModelHandle convertModelForGoal(unsigned index, Z3ModelHandle toConvert);
};
}
}
#endif
================================================
FILE: include/jfs/Core/Z3NodeMap.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_Z3_NODE_MAP_H
#define JFS_CORE_Z3_NODE_MAP_H
#include "jfs/Core/Z3ASTCmp.h"
#include
namespace jfs {
namespace core {
template
using Z3ASTMap = std::unordered_map;
template
using Z3SortMap = std::unordered_map;
template
using Z3FuncDeclMap =
std::unordered_map;
}
}
#endif
================================================
FILE: include/jfs/Core/Z3NodeSet.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_Z3_AST_SET_H
#define JFS_CORE_Z3_AST_SET_H
#include "jfs/Core/Z3ASTCmp.h"
#include "jfs/Core/Z3Node.h"
#include
#include
namespace jfs {
namespace core {
// We don't provide a templated Z3NodeSet because not all Z3Node's are ASTs.
// For now doing these aliases is simpler.
using Z3ASTSet = std::unordered_set;
using Z3FuncDeclSet =
std::unordered_set;
using Z3SortSet = std::unordered_set;
}
}
#endif
================================================
FILE: include/jfs/Core/Z3NodeUtil.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Alastair Donaldson
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_CORE_Z3NODE_UTIL_H
#define JFS_CORE_Z3NODE_UTIL_H
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeSet.h"
#include
namespace jfs {
namespace core {
class Z3NodeUtil {
public:
static void collectFuncDecls(Z3FuncDeclSet& addTo,
std::list& workList);
static void collectFuncDecls(Z3FuncDeclSet& addTo, Z3ASTHandle e);
template
static void collectFuncDecls(Z3FuncDeclSet& addTo, IteratorTy begin,
IteratorTy end) {
std::list workList;
for (IteratorTy b = begin, e = end; b != e; ++b) {
workList.push_back(*b);
}
collectFuncDecls(addTo, workList);
}
};
} // namespace core
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/BufferAssignment.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_BUFFER_ASSIGNMENT
#define JFS_FUZZING_COMMON_BUFFER_ASSIGNMENT
#include "jfs/Core/Query.h"
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeMap.h"
#include "jfs/Core/Z3NodeSet.h"
#include "jfs/FuzzingCommon/BufferElement.h"
#include
namespace jfs {
namespace fuzzingCommon {
class BufferAssignment {
private:
typedef std::vector ChunksTy;
ChunksTy chunks;
uint64_t cachedTypeBitWidth;
uint64_t cachedStoreBitWidth;
uint64_t computeTypeBitWidth() const;
uint64_t computeStoreBitWidth() const;
public:
BufferAssignment() : cachedTypeBitWidth(0), cachedStoreBitWidth(0) {}
~BufferAssignment() {}
void appendElement(BufferElement&);
uint64_t getTypeBitWidth() const { return cachedTypeBitWidth; }
uint64_t getStoreBitWidth() const { return cachedStoreBitWidth; }
uint64_t getRequiredStoreBytes() const {
return (getStoreBitWidth() + 7) / 8;
}
ChunksTy::const_iterator cbegin() const { return chunks.begin(); }
ChunksTy::const_iterator cend() const { return chunks.end(); }
ChunksTy::const_iterator begin() const { return cbegin(); }
ChunksTy::const_iterator end() const { return cend(); }
size_t size() const { return chunks.size(); }
void print(llvm::raw_ostream&) const;
void dump() const;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/BufferElement.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_BUFFER_ELEMENT
#define JFS_FUZZING_COMMON_BUFFER_ELEMENT
#include "jfs/Core/Query.h"
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeMap.h"
#include "jfs/Core/Z3NodeSet.h"
#include
namespace jfs {
namespace fuzzingCommon {
class BufferElement {
private:
size_t storeBitAlignment;
public:
const jfs::core::Z3ASTHandle declApp;
BufferElement(const jfs::core::Z3ASTHandle declApp,
size_t storeBitAlignment = 1);
unsigned getTypeBitWidth() const; // Does not include padding
unsigned getStoreBitWidth() const; // Includes any required padding
size_t getStoreBitAlignment() const { return storeBitAlignment; }
// FIXME: put this behind an interface once we know the requirements
std::vector equalities;
void print(llvm::raw_ostream&) const;
void dump() const;
jfs::core::Z3FuncDeclHandle getDecl() const;
std::string getName() const;
jfs::core::Z3SortHandle getSort() const;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/CmdLine/FreeVariableToBufferAssignmentPassOptionsBuilder.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_CMDLINE_FVTBAPOB_H
#define JFS_FUZZING_COMMON_CMDLINE_FVTBAPOB_H
#include "jfs/FuzzingCommon/FreeVariableToBufferAssignmentPassOptions.h"
#include
namespace jfs {
namespace fuzzingCommon {
namespace cl {
std::unique_ptr
buildFVTBAPOptionsFromCmdLine();
}
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/CmdLine/LibFuzzerOptionsBuilder.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_CMDLINE_LIBFUZZER_OPTIONS_BUILDER_H
#define JFS_FUZZING_COMMON_CMDLINE_LIBFUZZER_OPTIONS_BUILDER_H
#include "jfs/FuzzingCommon/LibFuzzerOptions.h"
#include
namespace jfs {
namespace fuzzingCommon {
namespace cl {
std::unique_ptr
buildLibFuzzerOptionsFromCmdLine();
}
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/CmdLine/SeedManagerOptionsBuilder.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_CMDLINE_SEED_MANAGER_OPTIONS_BUILDER_H
#define JFS_FUZZING_COMMON_CMDLINE_SEED_MANAGER_OPTIONS_BUILDER_H
#include "jfs/FuzzingCommon/SeedManager.h"
#include
namespace jfs {
namespace fuzzingCommon {
namespace cl {
std::unique_ptr
buildSeedManagerOptionsFromCmdLine();
}
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/CommandLineCategory.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_COMMAND_LINE_CATEGORY_H
#define JFS_FUZZING_COMMON_COMMAND_LINE_CATEGORY_H
#include "llvm/Support/CommandLine.h"
namespace jfs {
namespace fuzzingCommon {
extern llvm::cl::OptionCategory CommandLineCategory;
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/DummyFuzzingSolver.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_DUMMY_FUZZING_SOLVER
#define JFS_FUZZING_COMMON_DUMMY_FUZZING_SOLVER
#include "jfs/FuzzingCommon/FuzzingSolver.h"
namespace jfs {
namespace fuzzingCommon {
// This solver doesn't do any fuzzing so in effect
// it can only solve trivial constraints
class DummyFuzzingSolver : public FuzzingSolver {
protected:
std::unique_ptr
fuzz(jfs::core::Query& q, bool produceModel,
std::shared_ptr info) override;
public:
DummyFuzzingSolver(std::unique_ptr options,
std::unique_ptr wdm,
jfs::core::JFSContext& ctx);
~DummyFuzzingSolver();
llvm::StringRef getName() const override;
void cancel() override;
};
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/EqualityExtractionPass.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_EQUALITY_EXTRACTION_PASS_H
#define JFS_FUZZING_COMMON_EQUALITY_EXTRACTION_PASS_H
#include "jfs/Core/Query.h"
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeMap.h"
#include "jfs/Core/Z3NodeSet.h"
#include "jfs/Transform/QueryPass.h"
#include
namespace jfs {
namespace fuzzingCommon {
// This pass looks for simple equalities (e.g. `(= a b)`), removes them from
// the query and adds them to the known set of equalites. The motivation is
// that the fuzzer is very unlikely to guess at random to make two expressions
// equal. Instead of enforcing them as branch conditions we can construct the
// input program such the equality always holds in some simple cases.
class EqualityExtractionPass : public jfs::transform::QueryPass {
private:
void cleanUp();
public:
// TODO: Put this behind an interface once we know what the requirements
// are.
jfs::core::Z3ASTMap> mapping;
std::unordered_set> equalities;
EqualityExtractionPass();
~EqualityExtractionPass() {}
bool run(jfs::core::Query& q) override;
virtual llvm::StringRef getName() override;
virtual bool convertModel(jfs::core::Model* m) override;
};
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/FileSerializableModel.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Alastair Donaldson
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_FILE_SERIALIZABLE_MODEL_H
#define JFS_FUZZING_COMMON_FILE_SERIALIZABLE_MODEL_H
#include "jfs/Core/Model.h"
#include "jfs/Core/Z3Node.h"
#include "jfs/FuzzingCommon/BufferAssignment.h"
#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/Support/MemoryBuffer.h"
#include
namespace jfs {
namespace fuzzingCommon {
class FileSerializableModel : public jfs::core::Model {
public:
// Empty model
FileSerializableModel(jfs::core::JFSContext& ctx);
static std::unique_ptr
loadFrom(const llvm::MemoryBuffer* buf, const BufferAssignment* ba,
jfs::core::JFSContext& ctx);
bool saveTo(llvm::FileOutputBuffer* buf, const BufferAssignment* ba,
jfs::core::JFSContext& ctx);
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/FreeVariableToBufferAssignmentPass.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_FREE_VARIABLE_TO_BUFFER_ASSIGNMENT_PASS_H
#define JFS_FUZZING_COMMON_FREE_VARIABLE_TO_BUFFER_ASSIGNMENT_PASS_H
#include "jfs/Core/Query.h"
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeMap.h"
#include "jfs/Core/Z3NodeSet.h"
#include "jfs/FuzzingCommon/BufferAssignment.h"
#include "jfs/FuzzingCommon/EqualityExtractionPass.h"
#include "jfs/FuzzingCommon/FreeVariableToBufferAssignmentPassOptions.h"
#include "jfs/Transform/QueryPass.h"
#include
namespace jfs {
namespace fuzzingCommon {
class ConstantAssignment {
public:
// TODO: Put this behind an interface
jfs::core::Z3ASTMap assignments;
void print(llvm::raw_ostream&) const;
void dump() const;
};
class FreeVariableToBufferAssignmentPass : public jfs::transform::QueryPass {
private:
const EqualityExtractionPass& eep;
// raw ptr because we don't own storage
FreeVariableToBufferAssignmentPassOptions* options;
std::unique_ptr defaultOptions;
public:
FreeVariableToBufferAssignmentPass(
const EqualityExtractionPass&,
FreeVariableToBufferAssignmentPassOptions* options);
~FreeVariableToBufferAssignmentPass() {}
bool run(jfs::core::Query& q) override;
virtual llvm::StringRef getName() override;
// TODO: Put these behind an interface
std::shared_ptr bufferAssignment;
// FIXME: It's debatable whether we actually need this. The
// ConstantPropagation pass
// means that equalities like this will already be expanded in constraints.
// This means
// the free variables that have constant assignments will never be used once
// the
// EqualityExtractionPass has run and so constantAssignment is always empty.
std::shared_ptr constantAssignments;
virtual bool convertModel(jfs::core::Model* m) override;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/FreeVariableToBufferAssignmentPassOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_FREE_VARIABLE_TO_BUFFER_ASSIGNMENT_PASS_OPTIONS_H
#define JFS_FUZZING_COMMON_FREE_VARIABLE_TO_BUFFER_ASSIGNMENT_PASS_OPTIONS_H
#include
namespace jfs {
namespace fuzzingCommon {
class FreeVariableToBufferAssignmentPassOptions {
public:
enum class FreeVariableSortStrategyTy {
ALPHABETICAL,
FIRST_OBSERVED,
NONE, // Warning: Will likely be non-deterministic
};
size_t bufferElementBitAlignment = 1;
FreeVariableSortStrategyTy sortStrategy =
FreeVariableSortStrategyTy::FIRST_OBSERVED;
FreeVariableToBufferAssignmentPassOptions();
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/FuzzingAnalysisInfo.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_FUZZING_ANALYSIS_INFO_H
#define JFS_FUZZING_COMMON_FUZZING_ANALYSIS_INFO_H
#include "jfs/FuzzingCommon/EqualityExtractionPass.h"
#include "jfs/FuzzingCommon/FreeVariableToBufferAssignmentPass.h"
#include "jfs/Transform/QueryPassManager.h"
#include
namespace jfs {
namespace fuzzingCommon {
// This contains the necessary analysis info
// that a fuzzing solver needs.
class FuzzingAnalysisInfo {
public:
std::shared_ptr equalityExtraction;
std::shared_ptr freeVariableAssignment;
void addTo(jfs::transform::QueryPassManager& pm);
FuzzingAnalysisInfo(FreeVariableToBufferAssignmentPassOptions* fvtbapOptions);
~FuzzingAnalysisInfo();
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/FuzzingSolver.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_FUZZING_SOLVER_H
#define JFS_FUZZING_COMMON_FUZZING_SOLVER_H
#include "jfs/Core/Solver.h"
#include "jfs/FuzzingCommon/WorkingDirectoryManager.h"
#include
namespace jfs {
namespace fuzzingCommon {
class FuzzingAnalysisInfo;
class FuzzingSolverImpl;
class FuzzingSolver : public jfs::core::Solver {
private:
std::unique_ptr impl;
protected:
virtual std::unique_ptr
fuzz(jfs::core::Query& q, bool produceModel,
std::shared_ptr info) = 0;
std::unique_ptr wdm;
public:
FuzzingSolver(std::unique_ptr options,
std::unique_ptr wdm,
jfs::core::JFSContext& ctx);
~FuzzingSolver();
std::unique_ptr solve(const jfs::core::Query& q,
bool produceModel) override;
void cancel() override;
friend class FuzzingSolverImpl;
};
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/FuzzingSolverOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_FUZZING_SOLVER_OPTIONS_H
#define JFS_FUZZING_COMMON_FUZZING_SOLVER_OPTIONS_H
#include "jfs/Core/SolverOptions.h"
#include "jfs/FuzzingCommon/FreeVariableToBufferAssignmentPassOptions.h"
#include
namespace jfs {
namespace fuzzingCommon {
class FuzzingSolverOptions : public jfs::core::SolverOptions {
private:
std::unique_ptr fvtbapOptions;
protected:
// For subclasses
FuzzingSolverOptions(
std::unique_ptr fvtbapOptions,
bool debugSaveModel,
jfs::core::SolverOptions::SolverOptionKind thisKind);
public:
bool debugSaveModel;
FuzzingSolverOptions(
std::unique_ptr fvtbapOptions,
bool debugSaveModel);
static bool classof(const SolverOptions* so) {
return so->getKind() >= jfs::core::SolverOptions::FUZZING_SOLVER_KIND &&
so->getKind() < jfs::core::SolverOptions::LAST_FUZZING_SOLVER_KIND;
}
FreeVariableToBufferAssignmentPassOptions*
getFreeVariableToBufferAssignmentOptions() const;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/JFSRuntimeFuzzingStat.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_JFS_RUNTIME_FUZZING_STAT
#define JFS_FUZZING_COMMON_JFS_RUNTIME_FUZZING_STAT
#include "jfs/Core/JFSContext.h"
#include "jfs/FuzzingCommon/FuzzingSolver.h"
#include "jfs/Support/JFSStat.h"
#include "llvm/ADT/StringRef.h"
#include
namespace jfs {
namespace fuzzingCommon {
struct JFSRuntimeFuzzingStat : public jfs::support::JFSStat {
uint64_t maxNumConstraintsSatisfied;
static const char* maxNumConstraintsSatisfiedKeyName;
uint64_t numberOfInputsTried;
static const char* numberOfInputsTriedKeyName;
uint64_t numberOfWrongSizedInputsTried;
static const char* numberOfWrongSizedInputsTriedKeyName;
JFSRuntimeFuzzingStat(llvm::StringRef name);
virtual ~JFSRuntimeFuzzingStat();
void printYAML(llvm::ScopedPrinter& os) const override;
static bool classof(const JFSStat* s) { return s->getKind() == RUNTIME; }
static std::unique_ptr
LoadFromYAML(llvm::StringRef filePath, llvm::StringRef name,
jfs::core::JFSContext& ctx);
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/LibFuzzerInvocationManager.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_LIBFUZZER_INVOCATION_MANAGER_H
#define JFS_FUZZING_COMMON_LIBFUZZER_INVOCATION_MANAGER_H
#include "jfs/Core/JFSContext.h"
#include "jfs/FuzzingCommon/LibFuzzerOptions.h"
#include "jfs/Support/ICancellable.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MemoryBuffer.h"
#include
#include
namespace jfs {
namespace fuzzingCommon {
struct LibFuzzerResponse {
enum class ResponseTy {
TARGET_FOUND,
SINGLE_RUN_TARGET_NOT_FOUND,
RUN_BOUND_REACHED,
CANCELLED,
UNKNOWN,
};
ResponseTy outcome;
std::string pathToInput;
LibFuzzerResponse();
~LibFuzzerResponse();
// Returns nullptr if outcome was not `TARGET_FOUND`.
std::unique_ptr getInputForTarget() const;
};
class LibFuzzerInvocationManagerImpl;
class LibFuzzerInvocationManager : public jfs::support::ICancellable {
private:
const std::unique_ptr impl;
public:
LibFuzzerInvocationManager(jfs::core::JFSContext& ctx);
~LibFuzzerInvocationManager();
void cancel();
std::unique_ptr fuzz(const LibFuzzerOptions* options,
llvm::StringRef stdOutFile,
llvm::StringRef stdErrFile);
};
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/LibFuzzerOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_LIBFUZZER_OPTIONS_H
#define JFS_FUZZING_COMMON_LIBFUZZER_OPTIONS_H
#include
#include
namespace jfs {
namespace fuzzingCommon {
// FIXME: This design is broken. Some of these options are used internally and
// will get overwritten and others are public and can be changed. We need
// to separate these two concerns.
struct LibFuzzerOptions {
// NOTE: `runs` value of `0` means an infinite number of runs.
size_t runs; // Approximately corresponds to `-runs=` option.
uint64_t mutationDepth; // Corresponds to `-mutate_depth=`
bool crossOver; // Corresponds to `-cross_over` option
uint64_t maxLength; // Corresponds to `-max_len=` option (bytes).
bool useCmp; // Corresponds to `-use_cmp` option
bool printFinalStats; // Corresponds to `-print_final_stats=1`
bool reduceInputs; // Corresponds to `-reduce_inputs=1`
bool defaultMutationsResizeInput; // Corresponds to `default_mutators_resize_input=1`
bool handleSIGABRT;
bool handleSIGBUS;
bool handleSIGFPE;
bool handleSIGILL;
bool handleSIGINT;
bool handleSIGSEGV;
bool handleSIGTERM;
bool handleSIGXFSZ;
std::string targetBinary;
std::string artifactDir;
std::string corpusDir;
std::string jfsRuntimeLogFile;
// TODO: We should support LibFuzzer jobs/workers. This
// will require a vector of seeds rather than a single seed
LibFuzzerOptions();
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/SeedGenerator.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SEED_GENERATOR_H
#define JFS_FUZZING_COMMON_SEED_GENERATOR_H
#include "llvm/ADT/StringRef.h"
#include
namespace jfs {
namespace fuzzingCommon {
class FuzzingAnalysisInfo;
class SeedManager;
class SeedGenerator {
private:
std::string name;
public:
SeedGenerator(llvm::StringRef name);
virtual ~SeedGenerator();
// Called once by the SeedManager before any seeds are requested
virtual void preGenerationCallBack(SeedManager& sm);
// Called once by the SeedManager after all seeds are requested
virtual void postGenerationCallBack(SeedManager& sm);
// Returns true on success
virtual bool writeSeed(SeedManager& sm) = 0;
virtual llvm::StringRef getName() const { return name; }
virtual bool empty() const = 0;
};
// A generator that emits a single seed with all bytes set to
// the supplied byte value.
class AllBytesEqualGenerator : public SeedGenerator {
private:
uint8_t byteValue;
bool seedWritten;
public:
AllBytesEqualGenerator(llvm::StringRef name, uint8_t byteValue);
void preGenerationCallBack(SeedManager& sm) override {}
void postGenerationCallBack(SeedManager& sm) override {}
bool writeSeed(SeedManager& sm) override;
bool empty() const override;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/SeedManager.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SEED_MANAGER_H
#define JFS_FUZZING_COMMON_SEED_MANAGER_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Core/Query.h"
#include "jfs/Support/ICancellable.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/FileOutputBuffer.h"
#include
#include
namespace jfs {
namespace fuzzingCommon {
class SeedGenerator;
class SeedManagerImpl;
class FuzzingAnalysisInfo;
class SeedManagerOptions;
class SeedManager : jfs::support::ICancellable {
private:
std::unique_ptr impl;
public:
SeedManager(llvm::StringRef seedDir, jfs::core::JFSContext& ctx);
SeedManager(const SeedManager&) = delete;
~SeedManager();
void cancel() override;
void configureFrom(std::unique_ptr options);
void addSeedGenerator(std::unique_ptr sg);
// Returns number of written seeds.
uint64_t writeSeeds(const FuzzingAnalysisInfo* info,
const jfs::core::Query* q);
void setSpaceLimit(uint64_t maxSeedSpaceInBytes);
uint64_t getSpaceLimit() const;
void setMaxNumSeeds(uint64_t maxNumSeeds);
uint64_t getMaxNumSeeds() const;
// Create a FileOutputBuffer with the appropriate size and filename for the
// seed. The caller is responsible for calling commit.
//
// This is the preferred method writing a seed
std::unique_ptr
getBufferForSeed(llvm::StringRef prefix);
// Get and reserve a seed ID but don't actually create it.
std::string getAndReserveSeedID(llvm::StringRef prefix);
std::string getAndReserveSeedID();
jfs::core::JFSContext& getContext() const;
const FuzzingAnalysisInfo* getCurrentFuzzingAnalysisInfo() const;
const jfs::core::Query* getCurrentQuery() const;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/SeedManagerOptions.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SEED_MANAGER_OPTIONS_H
#define JFS_FUZZING_COMMON_SEED_MANAGER_OPTIONS_H
#include "jfs/FuzzingCommon/SeedGenerator.h"
#include
#include
namespace jfs {
namespace fuzzingCommon {
class SeedGenerator;
class SeedManagerOptions {
public:
uint64_t maxSeedSpaceInBytes;
uint64_t maxNumSeeds;
std::list> generators;
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/SeedManagerStat.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SEED_MANAGER_STAT_H
#define JFS_FUZZING_COMMON_SEED_MANAGER_STAT_H
#include "jfs/Core/JFSContext.h"
#include "jfs/FuzzingCommon/FuzzingSolver.h"
#include "jfs/Support/JFSStat.h"
#include "llvm/ADT/StringRef.h"
#include
namespace jfs {
namespace fuzzingCommon {
struct SeedManagerStat : public jfs::support::JFSStat {
uint64_t numSeedsGenerated = 0;
SeedManagerStat(llvm::StringRef name);
virtual ~SeedManagerStat();
void printYAML(llvm::ScopedPrinter& os) const override;
static bool classof(const JFSStat* s) { return s->getKind() == SEED_MANAGER; }
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/SortConformanceCheckPass.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SORT_CONFORMANCE_PASS_H
#define JFS_FUZZING_COMMON_SORT_CONFORMANCE_PASS_H
#include "jfs/Core/Query.h"
#include "jfs/Transform/QueryPass.h"
#include
namespace jfs {
namespace fuzzingCommon {
class SortConformanceCheckPass : public jfs::transform::QueryPass {
bool predicateHeld;
std::function predicate;
public:
SortConformanceCheckPass(
std::function predicate);
~SortConformanceCheckPass() {}
bool run(jfs::core::Query& q) override;
virtual llvm::StringRef getName() override;
bool predicateAlwaysHeld() const { return predicateHeld; }
void reset() { predicateHeld = false; }
virtual bool convertModel(jfs::core::Model* m) override;
};
}
}
#endif
================================================
FILE: include/jfs/FuzzingCommon/SpecialConstantSeedGenerator.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2018 J. Ryan Stinnett
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SPECIAL_CONSTANT_SEED_GENERATOR_H
#define JFS_FUZZING_COMMON_SPECIAL_CONSTANT_SEED_GENERATOR_H
#include "jfs/Core/Z3Node.h"
#include "jfs/Core/Z3NodeMap.h"
#include "jfs/FuzzingCommon/SeedGenerator.h"
#include "jfs/FuzzingCommon/SpecialConstantSeedGeneratorStat.h"
#include
namespace jfs {
namespace core {
class JFSContext;
class Model;
}
}
namespace jfs {
namespace fuzzingCommon {
class BufferElement;
class SeedManager;
// A seed generator that emits special constants based on the sorts used in the
// constraints of the query.
class SpecialConstantSeedGenerator : public SeedGenerator {
// Inherit constructor
using SeedGenerator::SeedGenerator;
void preGenerationCallBack(SeedManager& sm) override;
void postGenerationCallBack(SeedManager& sm) override;
bool writeSeed(SeedManager& sm) override;
bool empty() const override;
private:
// Track vectors of constants found in constraints by sort.
jfs::core::Z3SortMap>
sortToConstraintConstantMap;
std::unique_ptr stats;
bool chooseBool(core::JFSContext& ctx, const BufferElement& be,
core::Model& model);
bool chooseBitVector(core::JFSContext& ctx, const BufferElement& be,
core::Model& model);
bool chooseFloatingPoint(core::JFSContext& ctx, const BufferElement& be,
core::Model& model);
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/SpecialConstantSeedGeneratorStat.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Alastair Donaldson
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_SEED_GENERATOR_STAT_H
#define JFS_FUZZING_COMMON_SEED_GENERATOR_STAT_H
#include "jfs/Core/JFSContext.h"
#include "jfs/Core/Z3NodeMap.h"
#include "jfs/Support/JFSStat.h"
namespace jfs {
namespace fuzzingCommon {
struct SpecialConstantSeedGeneratorStat : public jfs::support::JFSStat {
jfs::core::Z3SortMap foundConstantsCount;
uint64_t totalNumBuiltInBVConstants = 0;
uint64_t numCoveredBVConstants = 0;
uint64_t totalNumBuiltInFPConstants = 0;
uint64_t numCoveredFPConstants = 0;
uint64_t totalNumBuiltInBoolConstants = 0;
uint64_t numCoveredBoolConstants = 0;
SpecialConstantSeedGeneratorStat(llvm::StringRef name);
virtual ~SpecialConstantSeedGeneratorStat();
void printYAML(llvm::ScopedPrinter& os) const override;
static bool classof(const JFSStat* s) {
return s->getKind() == SEED_GENERATOR;
}
};
} // namespace fuzzingCommon
} // namespace jfs
#endif
================================================
FILE: include/jfs/FuzzingCommon/WorkingDirectoryManager.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_FUZZING_COMMON_WORKING_DIRECTORY_MANAGER_H
#define JFS_FUZZING_COMMON_WORKING_DIRECTORY_MANAGER_H
#include "jfs/Core/JFSContext.h"
#include "llvm/ADT/StringRef.h"
#include
#include
namespace jfs {
namespace fuzzingCommon {
class WorkingDirectoryManager {
private:
const std::string path;
jfs::core::JFSContext& ctx;
const bool deleteOnDestruction;
WorkingDirectoryManager(llvm::StringRef path, jfs::core::JFSContext& ctx,
bool deleteOnDestruction);
public:
// Don't allow copying
~WorkingDirectoryManager();
WorkingDirectoryManager(const WorkingDirectoryManager&) = delete;
WorkingDirectoryManager(const WorkingDirectoryManager&&) = delete;
WorkingDirectoryManager& operator=(const WorkingDirectoryManager&) = delete;
llvm::StringRef getPath() const { return path; }
std::string getPathToFileInDirectory(llvm::StringRef fileName) const;
std::string makeNewDirectoryInDirectory(llvm::StringRef dirName);
// Make at `path`. `path` should not already exist, but its
// parent directory should.
// If the fails a nullptr will be returned.
static std::unique_ptr
makeAtPath(llvm::StringRef path, jfs::core::JFSContext& ctx,
bool deleteOnDestruction);
// Make at `/-N` where `N` is an integer.
// This function will start with `N == 0` an keep incrementing
// `N` until a directory is successfully created `N == maxN`.
// If the fails a nullptr will be returned.
static std::unique_ptr
makeInDirectory(llvm::StringRef directory, llvm::StringRef prefix,
jfs::core::JFSContext& ctx, bool deleteOnDestruction,
uint16_t maxN = 100);
};
}
}
#endif
================================================
FILE: include/jfs/Support/CancellableProcess.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_CANCELLABLE_PROCESS_H
#define JFS_SUPPORT_CANCELLABLE_PROCESS_H
#include "jfs/Support/ICancellable.h"
#include "llvm/ADT/StringRef.h"
#include
#include
#include
namespace jfs {
namespace support {
class CancellableProcessImpl;
// This is a thin wrapper around LLVM's
// `llvm::sys::ExecuteAndWait()` that supports
// cancellation.
class CancellableProcess : public ICancellable {
private:
const std::unique_ptr impl;
public:
CancellableProcess();
~CancellableProcess();
void cancel() override;
// Return values >= 0 is program exit code.
// Negative value indicates failure.
int execute(llvm::StringRef program, std::vector& args,
std::vector& redirects,
const char** envp = nullptr);
};
} // namespace support
} // namespace jfs
#endif
================================================
FILE: include/jfs/Support/ErrorMessages.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_ERROR_MESSAGES_H
#define JFS_SUPPORT_ERROR_MESSAGES_H
#include "llvm/ADT/StringRef.h"
#include
#include
namespace jfs {
namespace support {
std::string getMessageForFailedOpenFileOrSTDIN(llvm::StringRef inputFileName,
std::error_code ec);
std::string
getMessageForFailedOpenFileForWriting(llvm::StringRef outputFileName,
std::error_code ec);
}
}
#endif
================================================
FILE: include/jfs/Support/FileUtils.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_ERROR_MESSAGES_H
#define JFS_SUPPORT_ERROR_MESSAGES_H
#include "llvm/ADT/StringRef.h"
#include
#include
namespace jfs {
namespace support {
std::error_code recursive_remove(llvm::StringRef path, bool IgnoreNonExisting);
}
}
#endif
================================================
FILE: include/jfs/Support/ICancellable.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_ICANCELLABLE_H
#define JFS_SUPPORT_ICANCELLABLE_H
namespace jfs {
namespace support {
// This is a simple interface that classes can implement to cancel their
// currently assigned work. It is not defined what the state of the instance
// will be after making this call.
class ICancellable {
public:
virtual void cancel() = 0;
virtual ~ICancellable();
};
}
}
#endif
================================================
FILE: include/jfs/Support/JFSStat.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_JFS_STAT_H
#define JFS_SUPPORT_JFS_STAT_H
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/ScopedPrinter.h"
#include "llvm/Support/Timer.h"
#include "llvm/Support/raw_ostream.h"
#include
#include
#include
namespace jfs {
namespace support {
class JFSStat {
public:
enum JFSStatKind {
SINGLE_TIMER,
AGGREGATE_TIMER,
CXX_PROGRAM,
RUNTIME,
SEED_MANAGER,
SEED_GENERATOR
};
private:
const JFSStatKind kind;
std::string name;
protected:
JFSStat(JFSStatKind kind, llvm::StringRef name);
public:
virtual ~JFSStat();
JFSStatKind getKind() const { return kind; }
// FIXME: We should switch to llvm::yaml API.
virtual void printYAML(llvm::ScopedPrinter& os) const = 0;
void dump() const;
llvm::StringRef getName() const;
};
class JFSAggregateTimerStat;
class JFSTimerStat : public JFSStat {
private:
using RecordTy = llvm::TimeRecord;
RecordTy record;
public:
friend class JFSAggregateTimerStat;
JFSTimerStat(RecordTy record, llvm::StringRef name);
~JFSTimerStat();
void printYAML(llvm::ScopedPrinter& os) const override;
static bool classof(const JFSStat* s) { return s->getKind() == SINGLE_TIMER; }
};
class JFSAggregateTimerStat : public JFSStat {
private:
std::list> timers;
public:
JFSAggregateTimerStat(llvm::StringRef name);
~JFSAggregateTimerStat();
void append(std::unique_ptr t);
void clear();
void printYAML(llvm::ScopedPrinter& os) const override;
static bool classof(const JFSStat* s) {
return s->getKind() == AGGREGATE_TIMER;
}
};
}
}
#endif
================================================
FILE: include/jfs/Support/ScopedJFSTimerStatAppender.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_SCOPED_JFS_TIMER_STAT_APPENDER_H
#define JFS_SUPPORT_SCOPED_JFS_TIMER_STAT_APPENDER_H
#include "jfs/Support/JFSStat.h"
#include "jfs/Support/Timer.h"
#include
namespace jfs {
namespace support {
template class ScopedJFSTimerStatAppender {
public:
T* receiver;
Timer timer;
llvm::StringRef name;
std::unique_ptr result;
ScopedJFSTimerStatAppender(T* receiver, llvm::StringRef name)
: receiver(receiver), timer(), name(name), result(nullptr) {
if (receiver == nullptr)
return;
// Start timer
timer.startTimer();
}
~ScopedJFSTimerStatAppender() {
if (receiver == nullptr)
return;
timer.stopTimer();
result.reset(new JFSTimerStat(timer.getTotalTime(), name));
receiver->append(std::move(result));
}
};
template class ScopedJFSAggregateTimerStatAppender {
public:
T* receiver;
std::unique_ptr stats;
ScopedJFSAggregateTimerStatAppender(T* receiver, llvm::StringRef name)
: receiver(receiver), stats(nullptr) {
if (receiver == nullptr)
return;
stats.reset(new JFSAggregateTimerStat(name));
}
~ScopedJFSAggregateTimerStatAppender() {
if (receiver == nullptr)
return;
receiver->append(std::move(stats));
}
};
}
}
#endif
================================================
FILE: include/jfs/Support/ScopedTimer.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_SCOPED_TIMER_H
#define JFS_SUPPORT_SCOPED_TIMER_H
#include
#include
#include
namespace jfs {
namespace support {
class ScopedTimerImpl;
class ScopedTimer {
private:
std::unique_ptr impl;
public:
typedef std::function CallBackTy;
// Will call `callBack` if wall clock time exceeds
// `maxTime`. If `maxTime` is == 0 then `callBack`
// will never be called.
ScopedTimer(uint64_t maxTime, CallBackTy callBack);
~ScopedTimer();
uint64_t getRemainingTime() const;
uint64_t getMaxTime() const;
};
}
}
#endif
================================================
FILE: include/jfs/Support/StatisticsManager.h
================================================
//===----------------------------------------------------------------------===//
//
// JFS
//
// Copyright 2017-2018 Daniel Liew
//
// This file is distributed under the MIT license.
// See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef JFS_SUPPORT_STATISTICS_MANAGER_H
#define JFS_SUPPORT_STATISTICS_MANAGER_H
#include "llvm/Support/raw_ostream.h"
#include
namespace jfs {
namespace support {
class JFSStat;
class StatisticsManagerImpl;
class StatisticsManager {
private:
const std::unique_ptr impl;
public:
// FIXME: Figure out how to add iterators without leaking
// implementation details
StatisticsManager();
~StatisticsManager();
void append(std::unique_ptr