Differentially fuzz against z3.

This commit is contained in:
Bhargava Shastry 2022-02-15 11:05:46 +01:00
parent 3e88f7f85a
commit ea50fee663
4 changed files with 118 additions and 31 deletions

View File

@ -28,7 +28,7 @@ if (OSSFUZZ)
LPSolverFuzzer.cpp
LPSolverCustomMutatorInterface.cpp
)
target_link_libraries(lpsolver_ossfuzz PRIVATE solutil lpsolvergen)
target_link_libraries(lpsolver_ossfuzz PRIVATE solutil lpsolvergen z3)
set_target_properties(lpsolver_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
add_executable(solc_ossfuzz

View File

@ -113,21 +113,12 @@ extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size)
auto constraints = parseConstraints(input);
if (constraints.has_value())
{
// TODO: Z3 on constraints provided by fuzzer interface and comparing its outcome
// with LP solver.
FuzzerSolverInterface solverWithoutModels(/*supportModels=*/false);
FuzzerSolverInterface solverWithModels(/*supportModels=*/true);
solverWithoutModels.addConstraints(constraints.value());
string resultWithoutModels = solverWithoutModels.checkResult();
solverWithModels.addConstraints(constraints.value());
string resultWithModels = solverWithModels.checkResult();
if (resultWithoutModels != resultWithModels)
if (!solverWithModels.differentialCheck(constraints.value()))
{
cout << resultWithoutModels << endl;
cout << resultWithModels << endl;
solAssert(false, "LP result without models did not match with result with models.");
cout << solverWithModels.m_lpResult << endl;
cout << solverWithModels.m_z3Result << endl;
solAssert(false, "LP result did not match with z3 result.");
}
}
}

View File

@ -17,14 +17,21 @@
#include <range/v3/view/enumerate.hpp>
#include <set>
using namespace solidity::test::fuzzer::lpsolver;
using namespace solidity::util;
using namespace std;
using namespace z3;
FuzzerSolverInterface::FuzzerSolverInterface(bool _supportModels):
m_solver(_supportModels)
m_lpSolver(_supportModels),
m_z3Solver(m_z3Ctx)
{
m_solvingState.variableNames.emplace_back("");
m_lpSolvingState.variableNames.emplace_back("");
params z3Params(m_z3Ctx);
z3Params.set(":timeout", static_cast<unsigned>(10)); // in milliseconds
m_z3Solver.set(z3Params);
}
LinearExpression FuzzerSolverInterface::linearExpression(vector<int> _factors)
@ -36,26 +43,75 @@ LinearExpression FuzzerSolverInterface::linearExpression(vector<int> _factors)
return lexp;
}
void FuzzerSolverInterface::addConstraint(pair<bool, vector<int>> _constraint)
void FuzzerSolverInterface::addLPConstraint(pair<bool, vector<int>> _constraint)
{
m_solvingState.constraints.push_back({linearExpression(move(_constraint.second)), _constraint.first});
m_lpSolvingState.constraints.push_back({linearExpression(move(_constraint.second)), _constraint.first});
}
void FuzzerSolverInterface::addConstraints(vector<pair<bool, vector<int>>> _constraints)
void FuzzerSolverInterface::addZ3Constraint(pair<bool, vector<int>> _constraint)
{
bool isEquality = _constraint.first;
expr reduce = m_z3Ctx.real_val(0);
for (auto&& [index, value]: _constraint.second | ranges::views::enumerate)
{
if (index != 0 && value != 0)
{
string varName = "x" + to_string(index - 1);
expr var = m_z3Ctx.real_const(varName.c_str());
expr factor = m_z3Ctx.int_val(value);
reduce = reduce + var * factor;
m_z3Solver.add(var >= 0);
}
}
if (isEquality)
m_z3Solver.add(reduce == _constraint.second[0]);
else
m_z3Solver.add(reduce <= _constraint.second[0]);
}
void FuzzerSolverInterface::addLPConstraints(vector<pair<bool, vector<int>>> _constraints)
{
for (auto c: _constraints)
addConstraint(c);
addLPConstraint(c);
}
solution FuzzerSolverInterface::check()
void FuzzerSolverInterface::addZ3Constraints(vector<pair<bool, vector<int>>> _constraints)
{
return m_solver.check(m_solvingState);
for (auto c: _constraints)
addZ3Constraint(c);
}
string FuzzerSolverInterface::checkResult()
solution FuzzerSolverInterface::checkLP()
{
auto r = check();
return lpResult(r.first);
return m_lpSolver.check(m_lpSolvingState);
}
check_result FuzzerSolverInterface::checkZ3()
{
return m_z3Solver.check();
}
string FuzzerSolverInterface::checkLPResult()
{
m_lpResult = lpResult(checkLP().first);
return m_lpResult;
}
string FuzzerSolverInterface::checkZ3Result()
{
m_z3Result = z3Result(checkZ3());
return m_z3Result;
}
bool FuzzerSolverInterface::differentialCheck(vector<pair<bool, vector<int>>> _constraints)
{
addLPConstraints(_constraints);
addZ3Constraints(_constraints);
string z3Result = checkZ3Result();
string lpResult = checkLPResult();
bool checkFailed = ((z3Result == "infeasible") && (lpResult == "feasible")) ||
((z3Result == "feasible") && (lpResult == "infeasible"));
return !checkFailed;
}
string FuzzerSolverInterface::lpResult(LPResult _result)
@ -72,3 +128,18 @@ string FuzzerSolverInterface::lpResult(LPResult _result)
return "infeasible";
}
}
string FuzzerSolverInterface::z3Result(check_result _result)
{
switch (_result)
{
case check_result::unsat:
return "infeasible";
case check_result::sat:
return "feasible";
case check_result::unknown:
return "unknown";
default:
solAssert(false, "Invalid Z3 result");
}
}

View File

@ -21,6 +21,8 @@
#include <libsolutil/LP.h>
#include <libsolutil/LinearExpression.h>
#include <z3++.h>
#include <string>
namespace solidity::test::fuzzer::lpsolver
@ -37,25 +39,48 @@ public:
FuzzerSolverInterface(bool _supportModels);
/// Adds @param _constraint to LP solver.
void addConstraint(std::pair<bool, std::vector<int>> _constraint);
void addLPConstraint(std::pair<bool, std::vector<int>> _constraint);
/// Adds @param _constraint to Z3 solver.
void addZ3Constraint(std::pair<bool, std::vector<int>> _constraint);
/// Adds @param _constraints to LP solver.
void addConstraints(std::vector<std::pair<bool, std::vector<int>>> _constraints);
void addLPConstraints(std::vector<std::pair<bool, std::vector<int>>> _constraints);
/// Adds @param _constraints to Z3 solver.
void addZ3Constraints(std::vector<std::pair<bool, std::vector<int>>> _constraints);
/// @returns linear expression created from @param _factors.
solidity::util::LinearExpression linearExpression(std::vector<int> _factors);
/// Queries LP solver and @returns solution.
solution check();
solution checkLP();
/// Queries Z3 solver and @returns solution.
z3::check_result checkZ3();
/// Queries LP solver and @returns sat result as string.
std::string checkResult();
std::string checkLPResult();
/// Queries Z3 solver and @returns sat result as string.
std::string checkZ3Result();
/// @returns true if both the LP and the Z3 solver return an identical result on
/// @param _constraints, false otherwise.
bool differentialCheck(std::vector<std::pair<bool, std::vector<int>>> _constraints);
private:
/// @returns LP result as string.
std::string lpResult(solidity::util::LPResult _result);
solidity::util::LPSolver m_solver;
solidity::util::SolvingState m_solvingState;
/// @returns Z3 result as string.
std::string z3Result(z3::check_result _result);
solidity::util::LPSolver m_lpSolver;
solidity::util::SolvingState m_lpSolvingState;
z3::context m_z3Ctx;
z3::solver m_z3Solver;
public:
std::string m_lpResult;
std::string m_z3Result;
};
}