mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10913 from ethereum/refactor-solgen
Solidity fuzzer: Add test state.
This commit is contained in:
commit
4ff0069f41
@ -24,13 +24,12 @@
|
|||||||
using namespace solidity::test::fuzzer;
|
using namespace solidity::test::fuzzer;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using PrngUtil = solidity::test::fuzzer::GenerationProbability;
|
|
||||||
|
|
||||||
GeneratorBase::GeneratorBase(std::shared_ptr<SolidityGenerator> _mutator)
|
GeneratorBase::GeneratorBase(std::shared_ptr<SolidityGenerator> _mutator)
|
||||||
{
|
{
|
||||||
mutator = std::move(_mutator);
|
mutator = std::move(_mutator);
|
||||||
rand = mutator->randomEngine();
|
|
||||||
state = mutator->testState();
|
state = mutator->testState();
|
||||||
|
uRandDist = mutator->uniformRandomDist();
|
||||||
}
|
}
|
||||||
|
|
||||||
string GeneratorBase::visitChildren()
|
string GeneratorBase::visitChildren()
|
||||||
@ -38,9 +37,9 @@ string GeneratorBase::visitChildren()
|
|||||||
ostringstream os;
|
ostringstream os;
|
||||||
// Randomise visit order
|
// Randomise visit order
|
||||||
vector<GeneratorPtr> randomisedChildren;
|
vector<GeneratorPtr> randomisedChildren;
|
||||||
for (auto child: generators)
|
for (auto const& child: generators)
|
||||||
randomisedChildren.push_back(child);
|
randomisedChildren.push_back(child);
|
||||||
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *rand);
|
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist->randomEngine);
|
||||||
for (auto child: randomisedChildren)
|
for (auto child: randomisedChildren)
|
||||||
os << std::visit(GenericVisitor{
|
os << std::visit(GenericVisitor{
|
||||||
[&](auto const& _item) { return _item->generate(); }
|
[&](auto const& _item) { return _item->generate(); }
|
||||||
@ -52,7 +51,7 @@ string TestState::randomPath(set<string> const& _sourceUnitPaths) const
|
|||||||
{
|
{
|
||||||
auto it = _sourceUnitPaths.begin();
|
auto it = _sourceUnitPaths.begin();
|
||||||
/// Advance iterator by n where 0 <= n <= sourceUnitPaths.size() - 1
|
/// 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(
|
solAssert(
|
||||||
increment >= 0 && increment < _sourceUnitPaths.size(),
|
increment >= 0 && increment < _sourceUnitPaths.size(),
|
||||||
"Solc custom mutator: Invalid increment"
|
"Solc custom mutator: Invalid increment"
|
||||||
@ -104,7 +103,7 @@ void TestCaseGenerator::setup()
|
|||||||
string TestCaseGenerator::visit()
|
string TestCaseGenerator::visit()
|
||||||
{
|
{
|
||||||
ostringstream os;
|
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();
|
string sourcePath = path();
|
||||||
os << "\n"
|
os << "\n"
|
||||||
@ -140,7 +139,7 @@ string PragmaGenerator::visit()
|
|||||||
)";
|
)";
|
||||||
// Choose equally at random from coder v1 and v2
|
// Choose equally at random from coder v1 and v2
|
||||||
string abiPragma = "pragma abicoder v" +
|
string abiPragma = "pragma abicoder v" +
|
||||||
to_string(PrngUtil{}.distributionOneToN(2, rand)) +
|
to_string(uRandDist->distributionOneToN(2)) +
|
||||||
";\n";
|
";\n";
|
||||||
return preamble + abiPragma;
|
return preamble + abiPragma;
|
||||||
}
|
}
|
||||||
@ -157,7 +156,7 @@ string ImportGenerator::visit()
|
|||||||
// there is one source unit present in test.
|
// there is one source unit present in test.
|
||||||
if (state->size() == 1)
|
if (state->size() == 1)
|
||||||
{
|
{
|
||||||
if (PrngUtil{}.probable(s_selfImportInvProb, rand))
|
if (uRandDist->probable(s_selfImportInvProb))
|
||||||
os << "import "
|
os << "import "
|
||||||
<< "\""
|
<< "\""
|
||||||
<< state->randomPath()
|
<< state->randomPath()
|
||||||
@ -186,9 +185,9 @@ shared_ptr<T> SolidityGenerator::generator()
|
|||||||
|
|
||||||
SolidityGenerator::SolidityGenerator(unsigned _seed)
|
SolidityGenerator::SolidityGenerator(unsigned _seed)
|
||||||
{
|
{
|
||||||
m_rand = make_shared<RandomEngine>(_seed);
|
|
||||||
m_generators = {};
|
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>
|
template <size_t I>
|
||||||
|
@ -58,29 +58,34 @@ GENERATORLIST(VARIANTOFGENERATOR, COMMA(), )
|
|||||||
using RandomEngine = std::mt19937_64;
|
using RandomEngine = std::mt19937_64;
|
||||||
using Distribution = std::uniform_int_distribution<size_t>;
|
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
|
/// @returns an unsigned integer in the range [1, @param _n] chosen
|
||||||
/// uniformly at random.
|
/// 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.
|
/// @returns true with a probability of 1/(@param _n), false otherwise.
|
||||||
/// @param _n must be non zero.
|
/// @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, "");
|
solAssert(_n > 0, "");
|
||||||
return distributionOneToN(_n, _rand) == 1;
|
return distributionOneToN(_n) == 1;
|
||||||
}
|
}
|
||||||
|
std::unique_ptr<RandomEngine> randomEngine;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct TestState
|
struct TestState
|
||||||
{
|
{
|
||||||
explicit TestState(std::shared_ptr<RandomEngine> _rand):
|
explicit TestState(std::shared_ptr<UniformRandomDistribution> _urd):
|
||||||
sourceUnitPaths({}),
|
sourceUnitPaths({}),
|
||||||
currentSourceUnitPath({}),
|
currentSourceUnitPath({}),
|
||||||
rand(std::move(_rand))
|
uRandDist(std::move(_urd))
|
||||||
{}
|
{}
|
||||||
/// Adds @param _path to @name sourceUnitPaths updates
|
/// Adds @param _path to @name sourceUnitPaths updates
|
||||||
/// @name currentSourceUnitPath.
|
/// @name currentSourceUnitPath.
|
||||||
@ -95,25 +100,25 @@ struct TestState
|
|||||||
{
|
{
|
||||||
return sourceUnitPaths.empty();
|
return sourceUnitPaths.empty();
|
||||||
}
|
}
|
||||||
/// Returns the number of items in @name sourceUnitPaths.
|
/// @returns the number of items in @name sourceUnitPaths.
|
||||||
[[nodiscard]] size_t size() const
|
[[nodiscard]] size_t size() const
|
||||||
{
|
{
|
||||||
return sourceUnitPaths.size();
|
return sourceUnitPaths.size();
|
||||||
}
|
}
|
||||||
/// Prints test state to @param _os.
|
/// Prints test state to @param _os.
|
||||||
void print(std::ostream& _os) const;
|
void print(std::ostream& _os) const;
|
||||||
/// Returns a randomly chosen path from @param _sourceUnitPaths.
|
/// @returns a randomly chosen path from @param _sourceUnitPaths.
|
||||||
[[nodiscard]] std::string randomPath(std::set<std::string> const& _sourceUnitPaths) const;
|
[[nodiscard]] std::string randomPath(std::set<std::string> const& _sourceUnitPaths) const;
|
||||||
/// Returns a randomly chosen path from @name sourceUnitPaths.
|
/// @returns a randomly chosen path from @name sourceUnitPaths.
|
||||||
[[nodiscard]] std::string randomPath() const;
|
[[nodiscard]] std::string randomPath() const;
|
||||||
/// Returns a randomly chosen non current source unit path.
|
/// @returns a randomly chosen non current source unit path.
|
||||||
[[nodiscard]] std::string randomNonCurrentPath() const;
|
[[nodiscard]] std::string randomNonCurrentPath() const;
|
||||||
/// List of source paths in test input.
|
/// List of source paths in test input.
|
||||||
std::set<std::string> sourceUnitPaths;
|
std::set<std::string> sourceUnitPaths;
|
||||||
/// Source path being currently visited.
|
/// Source path being currently visited.
|
||||||
std::string currentSourceUnitPath;
|
std::string currentSourceUnitPath;
|
||||||
/// Random number generator.
|
/// Uniform random distribution.
|
||||||
std::shared_ptr<RandomEngine> rand;
|
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GeneratorBase
|
struct GeneratorBase
|
||||||
@ -127,15 +132,15 @@ struct GeneratorBase
|
|||||||
return std::get<std::shared_ptr<T>>(g);
|
return std::get<std::shared_ptr<T>>(g);
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
/// Returns test fragment created by this generator.
|
/// @returns test fragment created by this generator.
|
||||||
std::string generate()
|
std::string generate()
|
||||||
{
|
{
|
||||||
std::string generatedCode = visit();
|
std::string generatedCode = visit();
|
||||||
endVisit();
|
endVisit();
|
||||||
return generatedCode;
|
return generatedCode;
|
||||||
}
|
}
|
||||||
/// Virtual visitor that returns a string representing
|
/// @returns a string representing the generation of
|
||||||
/// the generation of the Solidity grammar element.
|
/// the Solidity grammar element.
|
||||||
virtual std::string visit() = 0;
|
virtual std::string visit() = 0;
|
||||||
/// Method called after visiting this generator. Used
|
/// Method called after visiting this generator. Used
|
||||||
/// for clearing state if necessary.
|
/// for clearing state if necessary.
|
||||||
@ -162,12 +167,12 @@ struct GeneratorBase
|
|||||||
}
|
}
|
||||||
/// Shared pointer to the mutator instance
|
/// Shared pointer to the mutator instance
|
||||||
std::shared_ptr<SolidityGenerator> mutator;
|
std::shared_ptr<SolidityGenerator> mutator;
|
||||||
/// Random engine shared by Solidity mutators
|
|
||||||
std::shared_ptr<RandomEngine> rand;
|
|
||||||
/// Set of generators used by this generator.
|
/// Set of generators used by this generator.
|
||||||
std::set<GeneratorPtr> generators;
|
std::set<GeneratorPtr> generators;
|
||||||
/// Shared ptr to global test state.
|
/// Shared ptr to global test state.
|
||||||
std::shared_ptr<TestState> state;
|
std::shared_ptr<TestState> state;
|
||||||
|
/// Uniform random distribution
|
||||||
|
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
||||||
};
|
};
|
||||||
|
|
||||||
class TestCaseGenerator: public GeneratorBase
|
class TestCaseGenerator: public GeneratorBase
|
||||||
@ -184,7 +189,7 @@ public:
|
|||||||
return "Test case generator";
|
return "Test case generator";
|
||||||
}
|
}
|
||||||
private:
|
private:
|
||||||
/// Returns a new source path name that is formed by concatenating
|
/// @returns a new source path name that is formed by concatenating
|
||||||
/// a static prefix @name m_sourceUnitNamePrefix, a monotonically
|
/// a static prefix @name m_sourceUnitNamePrefix, a monotonically
|
||||||
/// increasing counter starting from 0 and the postfix (extension)
|
/// increasing counter starting from 0 and the postfix (extension)
|
||||||
/// ".sol".
|
/// ".sol".
|
||||||
@ -252,18 +257,18 @@ class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator>
|
|||||||
public:
|
public:
|
||||||
explicit SolidityGenerator(unsigned _seed);
|
explicit SolidityGenerator(unsigned _seed);
|
||||||
|
|
||||||
/// Returns the generator of type @param T.
|
/// @returns the generator of type @param T.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::shared_ptr<T> generator();
|
std::shared_ptr<T> generator();
|
||||||
/// Returns a shared ptr to underlying random
|
/// @returns a shared ptr to underlying random
|
||||||
/// number generator.
|
/// number distribution.
|
||||||
std::shared_ptr<RandomEngine> randomEngine()
|
std::shared_ptr<UniformRandomDistribution> uniformRandomDist()
|
||||||
{
|
{
|
||||||
return m_rand;
|
return m_urd;
|
||||||
}
|
}
|
||||||
/// Returns a pseudo randomly generated test case.
|
/// @returns a pseudo randomly generated test case.
|
||||||
std::string generateTestProgram();
|
std::string generateTestProgram();
|
||||||
/// Returns shared ptr to global test state.
|
/// @returns shared ptr to global test state.
|
||||||
std::shared_ptr<TestState> testState()
|
std::shared_ptr<TestState> testState()
|
||||||
{
|
{
|
||||||
return m_state;
|
return m_state;
|
||||||
@ -282,11 +287,11 @@ private:
|
|||||||
{
|
{
|
||||||
m_generators.clear();
|
m_generators.clear();
|
||||||
}
|
}
|
||||||
/// Random number generator
|
|
||||||
std::shared_ptr<RandomEngine> m_rand;
|
|
||||||
/// Sub generators
|
/// Sub generators
|
||||||
std::set<GeneratorPtr> m_generators;
|
std::set<GeneratorPtr> m_generators;
|
||||||
/// Shared global test state
|
/// Shared global test state
|
||||||
std::shared_ptr<TestState> m_state;
|
std::shared_ptr<TestState> m_state;
|
||||||
|
/// Uniform random distribution
|
||||||
|
std::shared_ptr<UniformRandomDistribution> m_urd;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user