mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Potential fixes to memory leaks
This commit is contained in:
parent
07fdbb309b
commit
914fcedb77
@ -30,6 +30,12 @@ namespace solidity::test::fuzzer::mutator
|
||||
struct SolidityCustomMutatorInterface
|
||||
{
|
||||
SolidityCustomMutatorInterface(uint8_t* _data, size_t _size, size_t _maxSize, unsigned _seed);
|
||||
|
||||
~SolidityCustomMutatorInterface()
|
||||
{
|
||||
generator.reset();
|
||||
}
|
||||
|
||||
/// Generates Solidity test program, copies it into buffer
|
||||
/// provided by libFuzzer and @returns size of the test program.
|
||||
size_t generate();
|
||||
|
@ -33,11 +33,10 @@ using namespace solidity::test::fuzzer::mutator;
|
||||
using namespace solidity::util;
|
||||
using namespace std;
|
||||
|
||||
GeneratorBase::GeneratorBase(std::shared_ptr<SolidityGenerator> _mutator)
|
||||
GeneratorBase::GeneratorBase(SolidityGenerator* _mutator)
|
||||
{
|
||||
mutator = std::move(_mutator);
|
||||
mutator = _mutator;
|
||||
state = mutator->testState();
|
||||
uRandDist = mutator->uniformRandomDist();
|
||||
}
|
||||
|
||||
string GeneratorBase::visitChildren()
|
||||
@ -47,10 +46,10 @@ string GeneratorBase::visitChildren()
|
||||
vector<std::pair<GeneratorPtr, unsigned>> randomisedChildren;
|
||||
for (auto const& child: generators)
|
||||
randomisedChildren.push_back(child);
|
||||
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist->randomEngine);
|
||||
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist()->randomEngine);
|
||||
for (auto const& child: randomisedChildren)
|
||||
if (uRandDist->likely(child.second + 1))
|
||||
for (unsigned i = 0; i < uRandDist->distributionOneToN(child.second); i++)
|
||||
if (uRandDist()->likely(child.second + 1))
|
||||
for (unsigned i = 0; i < uRandDist()->distributionOneToN(child.second); i++)
|
||||
os << std::visit(GenericVisitor{
|
||||
[&](auto const& _item) { return _item->generate(); }
|
||||
}, child.first);
|
||||
@ -161,7 +160,7 @@ string PragmaGenerator::visit()
|
||||
// Add preamble
|
||||
pragmas.insert(string(s_preamble));
|
||||
// Choose either abicoder v1 or v2 but not both.
|
||||
pragmas.insert(s_abiPragmas[uRandDist->distributionOneToN(s_abiPragmas.size()) - 1]);
|
||||
pragmas.insert(s_abiPragmas[uRandDist()->distributionOneToN(s_abiPragmas.size()) - 1]);
|
||||
return boost::algorithm::join(pragmas, "\n") + "\n";
|
||||
}
|
||||
|
||||
@ -365,7 +364,7 @@ AssignmentStmtGenerator::AssignOp AssignmentStmtGenerator::assignOp(SolidityType
|
||||
else
|
||||
solAssert(false, "");
|
||||
|
||||
return possibleOps[uRandDist->distributionOneToN(possibleOps.size()) - 1];
|
||||
return possibleOps[uRandDist()->distributionOneToN(possibleOps.size()) - 1];
|
||||
}
|
||||
|
||||
string AssignmentStmtGenerator::assignOp(AssignOp _op)
|
||||
@ -426,7 +425,7 @@ void StatementGenerator::setup()
|
||||
|
||||
string StatementGenerator::visit()
|
||||
{
|
||||
bool unchecked = uRandDist->probable(s_uncheckedBlockInvProb);
|
||||
bool unchecked = uRandDist()->probable(s_uncheckedBlockInvProb);
|
||||
bool inUnchecked = mutator->generator<BlockStmtGenerator>()->unchecked();
|
||||
// Do not generate nested unchecked blocks.
|
||||
bool generateUncheckedBlock = unchecked && !inUnchecked;
|
||||
@ -438,9 +437,9 @@ string StatementGenerator::visit()
|
||||
vector<std::pair<GeneratorPtr, unsigned>> randomisedChildren;
|
||||
for (auto const& child: generators)
|
||||
randomisedChildren.push_back(child);
|
||||
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist->randomEngine);
|
||||
shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist()->randomEngine);
|
||||
for (auto const& child: randomisedChildren)
|
||||
if (uRandDist->likely(child.second + 1))
|
||||
if (uRandDist()->likely(child.second + 1))
|
||||
{
|
||||
os << std::visit(GenericVisitor{
|
||||
[](auto const& _item) { return _item->generate(); }
|
||||
@ -478,8 +477,9 @@ string BlockStmtGenerator::visit()
|
||||
block << indentation() + "{\n";
|
||||
|
||||
// Create blockscope inside current function state
|
||||
auto newBlockScope = make_shared<BlockScope>();
|
||||
state->currentFunctionState()->scopes.push_back(
|
||||
make_shared<BlockScope>()
|
||||
std::move(newBlockScope)
|
||||
);
|
||||
state->indent();
|
||||
block << visitChildren();
|
||||
@ -503,12 +503,12 @@ string FunctionGenerator::visit()
|
||||
visibility = "external";
|
||||
|
||||
// Add I/O
|
||||
if (uRandDist->likely(s_maxInputs + 1))
|
||||
for (unsigned i = 0; i < uRandDist->distributionOneToN(s_maxInputs); i++)
|
||||
if (uRandDist()->likely(s_maxInputs + 1))
|
||||
for (unsigned i = 0; i < uRandDist()->distributionOneToN(s_maxInputs); i++)
|
||||
state->currentFunctionState()->addInput(TypeProvider{state}.type());
|
||||
|
||||
if (uRandDist->likely(s_maxOutputs + 1))
|
||||
for (unsigned i = 0; i < uRandDist->distributionOneToN(s_maxOutputs); i++)
|
||||
if (uRandDist()->likely(s_maxOutputs + 1))
|
||||
for (unsigned i = 0; i < uRandDist()->distributionOneToN(s_maxOutputs); i++)
|
||||
state->currentFunctionState()->addOutput(TypeProvider{state}.type());
|
||||
|
||||
ostringstream function;
|
||||
@ -1253,7 +1253,7 @@ string FunctionCallGenerator::visit()
|
||||
if (availableFunctions.size() > 1)
|
||||
{
|
||||
for (auto const& i: availableFunctions)
|
||||
if (uRandDist->probable(availableFunctions.size()))
|
||||
if (uRandDist()->probable(availableFunctions.size()))
|
||||
callee = i;
|
||||
}
|
||||
else
|
||||
@ -1277,7 +1277,8 @@ shared_ptr<T> SolidityGenerator::generator()
|
||||
SolidityGenerator::SolidityGenerator(unsigned _seed)
|
||||
{
|
||||
m_generators = {};
|
||||
m_urd = make_shared<UniformRandomDistribution>(make_unique<RandomEngine>(_seed));
|
||||
auto engine = make_unique<RandomEngine>(_seed);
|
||||
m_urd = make_shared<UniformRandomDistribution>(std::move(engine));
|
||||
m_state = make_shared<TestState>(m_urd);
|
||||
}
|
||||
|
||||
@ -1299,6 +1300,5 @@ string SolidityGenerator::generateTestProgram()
|
||||
[&](auto const& _item) { return _item->setup(); }
|
||||
}, g);
|
||||
string program = generator<TestCaseGenerator>()->generate();
|
||||
destroyGenerators();
|
||||
return program;
|
||||
}
|
||||
|
@ -64,7 +64,7 @@ TYPELIST(VARIANTOFSHARED, COMMA(), )
|
||||
>;
|
||||
#undef VARIANTOFSHARED
|
||||
#undef COMMA
|
||||
using RandomEngine = std::mt19937_64;
|
||||
using RandomEngine = std::minstd_rand;
|
||||
using Distribution = std::uniform_int_distribution<size_t>;
|
||||
|
||||
struct UniformRandomDistribution
|
||||
@ -73,6 +73,11 @@ struct UniformRandomDistribution
|
||||
randomEngine(std::move(_randomEngine))
|
||||
{}
|
||||
|
||||
~UniformRandomDistribution()
|
||||
{
|
||||
randomEngine.reset();
|
||||
}
|
||||
|
||||
/// @returns an unsigned integer in the range [1, @param _n] chosen
|
||||
/// uniformly at random.
|
||||
[[nodiscard]] size_t distributionOneToN(size_t _n) const
|
||||
@ -408,6 +413,7 @@ struct SourceState
|
||||
importedSources.clear();
|
||||
freeFunctions.clear();
|
||||
exports.clear();
|
||||
uRandDist.reset();
|
||||
}
|
||||
/// Prints source state to @param _os.
|
||||
void print(std::ostream& _os) const;
|
||||
@ -448,20 +454,21 @@ struct FunctionState
|
||||
inputs.clear();
|
||||
outputs.clear();
|
||||
scopes.clear();
|
||||
type.reset();
|
||||
}
|
||||
void addInput(SolidityTypePtr _input)
|
||||
{
|
||||
type->addInput(_input);
|
||||
inputs.emplace_back(_input, "i" + std::to_string(numInputs++));
|
||||
inputs.emplace_back(std::move(_input), "i" + std::to_string(numInputs++));
|
||||
}
|
||||
void addOutput(SolidityTypePtr _output)
|
||||
{
|
||||
type->addOutput(_output);
|
||||
outputs.emplace_back(_output, "o" + std::to_string(numOutpus++));
|
||||
outputs.emplace_back(std::move(_output), "o" + std::to_string(numOutpus++));
|
||||
}
|
||||
void addLocal(SolidityTypePtr _local)
|
||||
{
|
||||
scopes.back()->variables.emplace_back(_local, "l" + std::to_string(numLocals++));
|
||||
scopes.back()->variables.emplace_back(std::move(_local), "l" + std::to_string(numLocals++));
|
||||
}
|
||||
std::string params(Params _p);
|
||||
|
||||
@ -487,6 +494,7 @@ struct ContractState
|
||||
~ContractState()
|
||||
{
|
||||
functions.clear();
|
||||
uRandDist.reset();
|
||||
}
|
||||
void addFunction(std::shared_ptr<FunctionState> _function)
|
||||
{
|
||||
@ -517,22 +525,24 @@ struct TestState
|
||||
/// @name currentSourceUnitPath.
|
||||
void addSourceUnit(std::string const& _path)
|
||||
{
|
||||
sourceUnitState.emplace(_path, std::make_shared<SourceState>(uRandDist, _path));
|
||||
auto sourceState = std::make_shared<SourceState>(uRandDist, _path);
|
||||
sourceUnitState.emplace(_path, std::move(sourceState));
|
||||
currentSourceUnitPath = _path;
|
||||
}
|
||||
/// Adds @param _name to @name contractState updates
|
||||
/// @name currentContract.
|
||||
void addContract(std::string const& _name)
|
||||
{
|
||||
contractState.emplace(_name, std::make_shared<ContractState>(uRandDist, _name));
|
||||
sourceUnitState[currentSourceUnitPath]->exports[
|
||||
std::make_shared<ContractType>(_name)
|
||||
] = _name;
|
||||
auto newContractState = std::make_shared<ContractState>(uRandDist, _name);
|
||||
contractState.emplace(_name, std::move(newContractState));
|
||||
auto newContractType = std::make_shared<ContractType>(_name);
|
||||
sourceUnitState[currentSourceUnitPath]->exports[std::move(newContractType)] = _name;
|
||||
currentContract = _name;
|
||||
}
|
||||
void addFunction(std::string const& _name, bool _freeFunction)
|
||||
{
|
||||
functionState.emplace(_name, std::make_shared<FunctionState>(_name, _freeFunction));
|
||||
auto fState = std::make_shared<FunctionState>(_name, _freeFunction);
|
||||
functionState.emplace(_name, std::move(fState));
|
||||
currentFunction = _name;
|
||||
}
|
||||
std::shared_ptr<FunctionState> currentFunctionState()
|
||||
@ -639,6 +649,7 @@ struct TestState
|
||||
sourceUnitState.clear();
|
||||
contractState.clear();
|
||||
functionState.clear();
|
||||
uRandDist.reset();
|
||||
}
|
||||
/// Prints test state to @param _os.
|
||||
void print(std::ostream& _os) const;
|
||||
@ -686,6 +697,11 @@ struct TypeProvider
|
||||
TypeProvider(std::shared_ptr<TestState> _state): state(std::move(_state))
|
||||
{}
|
||||
|
||||
~TypeProvider()
|
||||
{
|
||||
state.reset();
|
||||
}
|
||||
|
||||
enum class Type: size_t
|
||||
{
|
||||
INTEGER = 1,
|
||||
@ -729,6 +745,12 @@ struct LiteralGenerator
|
||||
{
|
||||
explicit LiteralGenerator(std::shared_ptr<TestState> _state): state(std::move(_state))
|
||||
{}
|
||||
|
||||
~LiteralGenerator()
|
||||
{
|
||||
state.reset();
|
||||
}
|
||||
|
||||
std::string operator()(std::shared_ptr<AddressType> const& _type);
|
||||
std::string operator()(std::shared_ptr<BoolType> const& _type);
|
||||
std::string operator()(std::shared_ptr<BytesType> const& _type);
|
||||
@ -745,6 +767,11 @@ struct ExpressionGenerator
|
||||
ExpressionGenerator(std::shared_ptr<TestState> _state): state(std::move(_state))
|
||||
{}
|
||||
|
||||
~ExpressionGenerator()
|
||||
{
|
||||
state.reset();
|
||||
}
|
||||
|
||||
enum class RLValueExpr: size_t
|
||||
{
|
||||
VARREF = 1,
|
||||
@ -825,9 +852,54 @@ struct ExpressionGenerator
|
||||
static constexpr unsigned s_maxNestingDepth = 30;
|
||||
};
|
||||
|
||||
class SolidityGenerator
|
||||
{
|
||||
public:
|
||||
explicit SolidityGenerator(unsigned _seed);
|
||||
|
||||
~SolidityGenerator()
|
||||
{
|
||||
m_generators.clear();
|
||||
m_urd.reset();
|
||||
m_state.reset();
|
||||
}
|
||||
|
||||
/// @returns the generator of type @param T.
|
||||
template <typename T>
|
||||
std::shared_ptr<T> generator();
|
||||
/// @returns a shared ptr to underlying random
|
||||
/// number distribution.
|
||||
std::shared_ptr<UniformRandomDistribution> uniformRandomDist()
|
||||
{
|
||||
return m_urd;
|
||||
}
|
||||
/// @returns a pseudo randomly generated test case.
|
||||
std::string generateTestProgram();
|
||||
/// @returns shared ptr to global test state.
|
||||
std::shared_ptr<TestState> testState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
private:
|
||||
template <typename T>
|
||||
void createGenerator()
|
||||
{
|
||||
auto generator = std::make_shared<T>(this);
|
||||
m_generators.insert(std::move(generator));
|
||||
}
|
||||
template <std::size_t I = 0>
|
||||
void createGenerators();
|
||||
/// 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;
|
||||
};
|
||||
|
||||
struct GeneratorBase
|
||||
{
|
||||
explicit GeneratorBase(std::shared_ptr<SolidityGenerator> _mutator);
|
||||
explicit GeneratorBase(SolidityGenerator* _mutator);
|
||||
template <typename T>
|
||||
std::shared_ptr<T> generator()
|
||||
{
|
||||
@ -863,7 +935,7 @@ struct GeneratorBase
|
||||
/// this grammar element.
|
||||
void addGenerators(std::set<std::pair<GeneratorPtr, unsigned>> _generators)
|
||||
{
|
||||
generators += _generators;
|
||||
generators += std::move(_generators);
|
||||
}
|
||||
/// Virtual method to obtain string name of generator.
|
||||
virtual std::string name() = 0;
|
||||
@ -874,21 +946,25 @@ struct GeneratorBase
|
||||
virtual ~GeneratorBase()
|
||||
{
|
||||
generators.clear();
|
||||
state.reset();
|
||||
}
|
||||
std::shared_ptr<UniformRandomDistribution> uRandDist()
|
||||
{
|
||||
return mutator->uniformRandomDist();
|
||||
}
|
||||
|
||||
/// Shared pointer to the mutator instance
|
||||
std::shared_ptr<SolidityGenerator> mutator;
|
||||
SolidityGenerator* mutator;
|
||||
/// Set of generators used by this generator.
|
||||
std::set<std::pair<GeneratorPtr, unsigned>> generators;
|
||||
/// Shared ptr to global test state.
|
||||
std::shared_ptr<TestState> state;
|
||||
/// Uniform random distribution
|
||||
std::shared_ptr<UniformRandomDistribution> uRandDist;
|
||||
};
|
||||
|
||||
class TestCaseGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit TestCaseGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit TestCaseGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
void setup() override;
|
||||
@ -924,7 +1000,7 @@ private:
|
||||
class SourceUnitGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit SourceUnitGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit SourceUnitGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
void setup() override;
|
||||
@ -938,7 +1014,7 @@ private:
|
||||
class PragmaGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit PragmaGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit PragmaGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
std::string visit() override;
|
||||
@ -954,7 +1030,7 @@ private:
|
||||
class ImportGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit ImportGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit ImportGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
std::string visit() override;
|
||||
@ -964,7 +1040,7 @@ public:
|
||||
class ContractGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit ContractGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit ContractGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
void setup() override;
|
||||
@ -977,7 +1053,7 @@ private:
|
||||
class FunctionGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit FunctionGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit FunctionGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator)),
|
||||
m_freeFunction(true)
|
||||
{}
|
||||
@ -1000,7 +1076,7 @@ private:
|
||||
class StatementGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit StatementGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit StatementGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
void setup() override;
|
||||
@ -1029,7 +1105,7 @@ public:
|
||||
ASSIGNMOD,
|
||||
ASSIGNMAX
|
||||
};
|
||||
explicit AssignmentStmtGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit AssignmentStmtGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
std::string visit() override;
|
||||
@ -1042,7 +1118,7 @@ private:
|
||||
class BlockStmtGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
explicit BlockStmtGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
explicit BlockStmtGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator)),
|
||||
m_nestingDepth(0),
|
||||
m_unchecked(false),
|
||||
@ -1095,7 +1171,7 @@ private:
|
||||
class FunctionCallGenerator: public GeneratorBase
|
||||
{
|
||||
public:
|
||||
FunctionCallGenerator(std::shared_ptr<SolidityGenerator> _mutator):
|
||||
FunctionCallGenerator(SolidityGenerator* _mutator):
|
||||
GeneratorBase(std::move(_mutator))
|
||||
{}
|
||||
std::string visit() override;
|
||||
@ -1108,47 +1184,4 @@ private:
|
||||
std::optional<std::string> rhs(std::vector<std::pair<SolidityTypePtr, std::string>> _functionInputTypeNames);
|
||||
std::string callStmt(std::shared_ptr<FunctionState> _callee);
|
||||
};
|
||||
|
||||
class SolidityGenerator: public std::enable_shared_from_this<SolidityGenerator>
|
||||
{
|
||||
public:
|
||||
explicit SolidityGenerator(unsigned _seed);
|
||||
|
||||
/// @returns the generator of type @param T.
|
||||
template <typename T>
|
||||
std::shared_ptr<T> generator();
|
||||
/// @returns a shared ptr to underlying random
|
||||
/// number distribution.
|
||||
std::shared_ptr<UniformRandomDistribution> uniformRandomDist()
|
||||
{
|
||||
return m_urd;
|
||||
}
|
||||
/// @returns a pseudo randomly generated test case.
|
||||
std::string generateTestProgram();
|
||||
/// @returns shared ptr to global test state.
|
||||
std::shared_ptr<TestState> testState()
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
private:
|
||||
template <typename T>
|
||||
void createGenerator()
|
||||
{
|
||||
m_generators.insert(
|
||||
std::make_shared<T>(shared_from_this())
|
||||
);
|
||||
}
|
||||
template <std::size_t I = 0>
|
||||
void createGenerators();
|
||||
void destroyGenerators()
|
||||
{
|
||||
m_generators.clear();
|
||||
}
|
||||
/// 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;
|
||||
};
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user