Create fuzzer solver interface and add constraint generator.

This commit is contained in:
Bhargava Shastry 2021-01-04 17:04:04 +01:00 committed by Bhargava Shastry
parent be9e2d320a
commit 11a903d330
9 changed files with 411 additions and 0 deletions

View File

@ -9,6 +9,7 @@ add_dependencies(ossfuzz
)
if (OSSFUZZ)
add_subdirectory(lpsolver)
add_custom_target(ossfuzz_proto)
add_dependencies(ossfuzz_proto
sol_proto_ossfuzz
@ -23,6 +24,13 @@ if (OSSFUZZ)
endif()
if (OSSFUZZ)
add_executable(lpsolver_ossfuzz
LPSolverFuzzer.cpp
LPSolverCustomMutatorInterface.cpp
)
target_link_libraries(lpsolver_ossfuzz PRIVATE solutil lpsolvergen)
set_target_properties(lpsolver_ossfuzz PROPERTIES LINK_FLAGS ${LIB_FUZZING_ENGINE})
add_executable(solc_ossfuzz
solc_ossfuzz.cpp
../fuzzer_common.cpp

View File

@ -0,0 +1,71 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <test/tools/ossfuzz/LPSolverCustomMutatorInterface.h>
#include <test/tools/ossfuzz/lpsolver/ConstraintGenerator.h>
#include <liblangutil/Exceptions.h>
using namespace std;
using namespace solidity::test::fuzzer::lpsolver;
// Prototype as we can't use the FuzzerInterface.h header.
extern "C" size_t LLVMFuzzerMutate(uint8_t* _data, size_t _size, size_t _maxSize);
extern "C" size_t LLVMFuzzerCustomMutator(uint8_t* _data, size_t size, size_t _maxSize, unsigned int seed);
namespace
{
/// Define LP Solver's custom mutator by implementing libFuzzer's
/// custom mutator external interface.
extern "C" size_t LLVMFuzzerCustomMutator(
uint8_t* _data,
size_t _size,
size_t _maxSize,
unsigned int _seed
)
{
solAssert(_data, "libFuzzerInterface: libFuzzer supplied bad buffer");
if (_maxSize <= _size || _size == 0)
return LLVMFuzzerMutate(_data, _size, _maxSize);
return LPSolverCustomMutatorInterface{_data, _size, _maxSize, _seed}.generate();
}
}
LPSolverCustomMutatorInterface::LPSolverCustomMutatorInterface(
uint8_t* _data,
size_t _size,
size_t _maxSize,
unsigned int _seed
):
data(_data),
size(_size),
maxMutantSize(_maxSize),
generator(make_shared<ConstraintGenerator>(_seed))
{}
size_t LPSolverCustomMutatorInterface::generate()
{
string testCase = generator->generate();
solAssert(
!testCase.empty() && data,
"Solc custom mutator: Invalid mutant or memory pointer"
);
size_t mutantSize = min(testCase.size(), maxMutantSize - 1);
mempcpy(data, testCase.data(), mutantSize);
return mutantSize;
}

View File

@ -0,0 +1,46 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Implements libFuzzer's custom mutator interface for LP Solver fuzzer.
*/
#pragma once
#include <test/tools/ossfuzz/lpsolver/ConstraintGenerator.h>
#include <memory>
namespace solidity::test::fuzzer::lpsolver
{
struct LPSolverCustomMutatorInterface
{
LPSolverCustomMutatorInterface(uint8_t* _data, size_t _size, size_t _maxSize, unsigned _seed);
/// Generates LP Solver constraints, copies it into buffer
/// provided by libFuzzer and @returns size of the test program.
size_t generate();
/// Raw pointer to libFuzzer provided input
uint8_t* data;
/// Size of libFuzzer provided input
size_t size;
/// Maximum length of mutant specified by libFuzzer
size_t maxMutantSize;
/// Constraint generator handle
std::shared_ptr<ConstraintGenerator> generator;
};
}

View File

@ -0,0 +1,32 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <cstddef>
#include <stdint.h>
using namespace std;
// Prototype as we can't use the FuzzerInterface.h header.
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* _data, size_t _size);
extern "C" int LLVMFuzzerTestOneInput(uint8_t const* , size_t )
{
// TODO: Invoke LP solver and Z3 on constraints provided by fuzzer interface,
// comparing their outcomes.
return 0;
}

View File

@ -0,0 +1,12 @@
set(sources
ConstraintGenerator.cpp
ConstraintGenerator.h
FuzzerSolverInterface.cpp
FuzzerSolverInterface.h
)
add_library(lpsolvergen)
target_sources(lpsolvergen
PUBLIC
${sources}
)
target_link_libraries(lpsolvergen PUBLIC solutil)

View File

@ -0,0 +1,41 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <test/tools/ossfuzz/lpsolver/ConstraintGenerator.h>
using namespace std;
using namespace solidity::test::fuzzer::lpsolver;
ConstraintGenerator::ConstraintGenerator(unsigned int _seed)
{
prng = make_shared<RandomEngine>(_seed);
}
string ConstraintGenerator::generate()
{
string constraint;
for (int i = 0; i < numConstraints(); i++)
{
string sep;
for (int j = 0; j < numFactors(); j++)
{
constraint += sep + to_string(randomInteger());
if (sep.empty())
sep = ", ";
}
constraint += "\n";
}
return constraint;
}

View File

@ -0,0 +1,65 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/*
* Generates an integer matrix of dimension n x m
*/
#pragma once
#include <limits>
#include <memory>
#include <random>
#include <string>
namespace solidity::test::fuzzer::lpsolver
{
using RandomEngine = std::mt19937;
using Distribution = std::uniform_int_distribution<int>;
struct ConstraintGenerator
{
explicit ConstraintGenerator(unsigned int _seed);
/// @returns generated constraint.
std::string generate();
/// @returns random number of factors.
int numFactors()
{
return Distribution(s_minFactors, s_maxFactors)(*prng);
}
/// @returns random number of constraints.
int numConstraints()
{
return Distribution(s_minConstraints, s_maxConstraints)(*prng);
}
/// @returns an integer chosen uniformly at random.
int randomInteger()
{
return Distribution(std::numeric_limits<int>::min(), std::numeric_limits<int>::max())(*prng);
}
std::shared_ptr<RandomEngine> prng;
static constexpr int s_minFactors = 2;
static constexpr int s_maxFactors = 10;
static constexpr int s_minConstraints = 1;
static constexpr int s_maxConstraints = 10;
};
}

View File

@ -0,0 +1,66 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <test/tools/ossfuzz/lpsolver/FuzzerSolverInterface.h>
using namespace solidity::test::fuzzer::lpsolver;
using namespace solidity::util;
using namespace std;
FuzzerSolverInterface::FuzzerSolverInterface()
{
m_solvingState.variableNames.emplace_back("");
}
LinearExpression FuzzerSolverInterface::constant(rational _value)
{
return LinearExpression::factorForVariable(0, _value);
}
LinearExpression FuzzerSolverInterface::variable(
rational _factor,
string const& _variable
)
{
return LinearExpression::factorForVariable(variableIndex(_variable), _factor);
}
void FuzzerSolverInterface::addLEConstraint(LinearExpression _lhs)
{
m_solvingState.constraints.push_back({move(_lhs), false});
}
void FuzzerSolverInterface::addEQConstraint(LinearExpression _lhs)
{
m_solvingState.constraints.push_back({move(_lhs), true});
}
solution FuzzerSolverInterface::check()
{
return m_solver.check(m_solvingState);
}
size_t FuzzerSolverInterface::variableIndex(string const& _name)
{
if (m_solvingState.variableNames.empty())
m_solvingState.variableNames.emplace_back("");
auto index = findOffset(m_solvingState.variableNames, _name);
if (!index)
{
index = m_solvingState.variableNames.size();
m_solvingState.variableNames.emplace_back(_name);
}
return *index;
}

View File

@ -0,0 +1,70 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Implements the Fuzzer-Solver interface.
*/
#pragma once
#include <libsolutil/LP.h>
#include <libsolutil/LinearExpression.h>
#include <string>
namespace solidity::test::fuzzer::lpsolver
{
using solution = std::pair<
solidity::util::LPResult,
std::map<std::string, solidity::util::rational>
>;
class FuzzerSolverInterface
{
public:
FuzzerSolverInterface();
/// @returns constant rational.
solidity::util::LinearExpression constant(solidity::util::rational _rationalConstant);
/// @returns linear expression that equals zero.
solidity::util::LinearExpression zero()
{
return constant(0);
}
/// @returns product of a rational factor and variable.
solidity::util::LinearExpression variable(
solidity::util::rational _factor,
std::string const& _variable
);
/// Adds less-than-equal-zero constraint to solver.
void addLEConstraint(solidity::util::LinearExpression _lhs);
/// Adds equal-to-zero constraint to solver.
void addEQConstraint(solidity::util::LinearExpression _lhs);
/// Queries LP solver and @returns solution.
solution check();
private:
/// Adds variable if necessary to LP solver state and @returns index of variable.
size_t variableIndex(std::string const& _name);
solidity::util::LPSolver m_solver;
solidity::util::SolvingState m_solvingState;
};
}