Solidity fuzzer: Add test state.

This commit is contained in:
Bhargava Shastry 2021-01-27 14:55:30 +01:00
parent ec62d12319
commit 896de75bcb
2 changed files with 31 additions and 27 deletions

View File

@ -24,13 +24,12 @@
using namespace solidity::test::fuzzer;
using namespace solidity::util;
using namespace std;
using PrngUtil = solidity::test::fuzzer::GenerationProbability;
GeneratorBase::GeneratorBase(std::shared_ptr<SolidityGenerator> _mutator)
{
mutator = std::move(_mutator);
rand = mutator->randomEngine();
state = mutator->testState();
uRandDist = mutator->uniformRandomDist();
}
string GeneratorBase::visitChildren()
@ -38,9 +37,9 @@ string GeneratorBase::visitChildren()
ostringstream os;
// Randomise visit order
vector<GeneratorPtr> randomisedChildren;
for (auto child: generators)
for (auto const& child: generators)
randomisedChildren.push_back(child);
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *rand);
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist->randomEngine);
for (auto child: randomisedChildren)
os << std::visit(GenericVisitor{
[&](auto const& _item) { return _item->generate(); }
@ -52,7 +51,7 @@ string TestState::randomPath(set<string> const& _sourceUnitPaths) const
{
auto it = _sourceUnitPaths.begin();
/// Advance iterator by n where 0 <= n <= sourceUnitPaths.size() - 1
size_t increment = PrngUtil{}.distributionOneToN(_sourceUnitPaths.size(), rand) - 1;
size_t increment = uRandDist->distributionOneToN(_sourceUnitPaths.size()) - 1;
solAssert(
increment >= 0 && increment < _sourceUnitPaths.size(),
"Solc custom mutator: Invalid increment"
@ -104,7 +103,7 @@ void TestCaseGenerator::setup()
string TestCaseGenerator::visit()
{
ostringstream os;
for (unsigned i = 0; i < PrngUtil{}.distributionOneToN(s_maxSourceUnits, rand); i++)
for (unsigned i = 0; i < uRandDist->distributionOneToN(s_maxSourceUnits); i++)
{
string sourcePath = path();
os << "\n"
@ -140,7 +139,7 @@ string PragmaGenerator::visit()
)";
// Choose equally at random from coder v1 and v2
string abiPragma = "pragma abicoder v" +
to_string(PrngUtil{}.distributionOneToN(2, rand)) +
to_string(uRandDist->distributionOneToN(2)) +
";\n";
return preamble + abiPragma;
}
@ -157,7 +156,7 @@ string ImportGenerator::visit()
// there is one source unit present in test.
if (state->size() == 1)
{
if (PrngUtil{}.probable(s_selfImportInvProb, rand))
if (uRandDist->probable(s_selfImportInvProb))
os << "import "
<< "\""
<< state->randomPath()
@ -186,9 +185,9 @@ shared_ptr<T> SolidityGenerator::generator()
SolidityGenerator::SolidityGenerator(unsigned _seed)
{
m_rand = make_shared<RandomEngine>(_seed);
m_generators = {};
m_state = make_shared<TestState>(m_rand);
m_urd = make_shared<UniformRandomDistribution>(make_unique<RandomEngine>(_seed));
m_state = make_shared<TestState>(m_urd);
}
template <size_t I>

View File

@ -58,29 +58,34 @@ GENERATORLIST(VARIANTOFGENERATOR, COMMA(), )
using RandomEngine = std::mt19937_64;
using Distribution = std::uniform_int_distribution<size_t>;
struct GenerationProbability
struct UniformRandomDistribution
{
explicit UniformRandomDistribution(std::unique_ptr<RandomEngine> _randomEngine):
randomEngine(std::move(_randomEngine))
{}
/// @returns an unsigned integer in the range [1, @param _n] chosen
/// uniformly at random.
static size_t distributionOneToN(size_t _n, std::shared_ptr<RandomEngine> const& _rand)
[[nodiscard]] size_t distributionOneToN(size_t _n) const
{
return Distribution(1, _n)(*_rand);
return Distribution(1, _n)(*randomEngine);
}
/// @returns true with a probability of 1/(@param _n), false otherwise.
/// @param _n must be non zero.
static bool probable(size_t _n, std::shared_ptr<RandomEngine> const& _rand)
[[nodiscard]] bool probable(size_t _n) const
{
solAssert(_n > 0, "");
return distributionOneToN(_n, _rand) == 1;
return distributionOneToN(_n) == 1;
}
std::unique_ptr<RandomEngine> randomEngine;
};
struct TestState
{
explicit TestState(std::shared_ptr<RandomEngine> _rand):
explicit TestState(std::shared_ptr<UniformRandomDistribution> _urd):
sourceUnitPaths({}),
currentSourceUnitPath({}),
rand(std::move(_rand))
uRandDist(std::move(_urd))
{}
/// Adds @param _path to @name sourceUnitPaths updates
/// @name currentSourceUnitPath.
@ -89,7 +94,7 @@ struct TestState
sourceUnitPaths.insert(_path);
currentSourceUnitPath = _path;
}
/// @returns true if @name sourceUnitPaths is empty,
/// Returns true if @name sourceUnitPaths is empty,
/// false otherwise.
[[nodiscard]] bool empty() const
{
@ -112,8 +117,8 @@ struct TestState
std::set<std::string> sourceUnitPaths;
/// Source path being currently visited.
std::string currentSourceUnitPath;
/// Random number generator.
std::shared_ptr<RandomEngine> rand;
/// Uniform random distribution.
std::shared_ptr<UniformRandomDistribution> uRandDist;
};
struct GeneratorBase
@ -162,12 +167,12 @@ struct GeneratorBase
}
/// Shared pointer to the mutator instance
std::shared_ptr<SolidityGenerator> mutator;
/// Random engine shared by Solidity mutators
std::shared_ptr<RandomEngine> rand;
/// Set of generators used by this generator.
std::set<GeneratorPtr> generators;
/// Shared ptr to global test state.
std::shared_ptr<TestState> state;
/// Uniform random distribution
std::shared_ptr<UniformRandomDistribution> uRandDist;
};
class TestCaseGenerator: public GeneratorBase
@ -256,10 +261,10 @@ public:
template <typename T>
std::shared_ptr<T> generator();
/// Returns a shared ptr to underlying random
/// number generator.
std::shared_ptr<RandomEngine> randomEngine()
/// number distribution.
std::shared_ptr<UniformRandomDistribution> uniformRandomDist()
{
return m_rand;
return m_urd;
}
/// Returns a pseudo randomly generated test case.
std::string generateTestProgram();
@ -282,11 +287,11 @@ private:
{
m_generators.clear();
}
/// Random number generator
std::shared_ptr<RandomEngine> m_rand;
/// Sub generators
std::set<GeneratorPtr> m_generators;
/// Shared global test state
std::shared_ptr<TestState> m_state;
/// Uniform random distribution
std::shared_ptr<UniformRandomDistribution> m_urd;
};
}