diff --git a/test/tools/ossfuzz/SolidityCustomMutatorInterface.h b/test/tools/ossfuzz/SolidityCustomMutatorInterface.h index 9cdbf505f..92ff8ad85 100644 --- a/test/tools/ossfuzz/SolidityCustomMutatorInterface.h +++ b/test/tools/ossfuzz/SolidityCustomMutatorInterface.h @@ -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(); diff --git a/test/tools/ossfuzz/SolidityGenerator.cpp b/test/tools/ossfuzz/SolidityGenerator.cpp index 22d841bed..3a3f80603 100644 --- a/test/tools/ossfuzz/SolidityGenerator.cpp +++ b/test/tools/ossfuzz/SolidityGenerator.cpp @@ -33,11 +33,10 @@ using namespace solidity::test::fuzzer::mutator; using namespace solidity::util; using namespace std; -GeneratorBase::GeneratorBase(std::shared_ptr _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> 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()->unchecked(); // Do not generate nested unchecked blocks. bool generateUncheckedBlock = unchecked && !inUnchecked; @@ -438,9 +437,9 @@ string StatementGenerator::visit() vector> 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(); state->currentFunctionState()->scopes.push_back( - make_shared() + 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 SolidityGenerator::generator() SolidityGenerator::SolidityGenerator(unsigned _seed) { m_generators = {}; - m_urd = make_shared(make_unique(_seed)); + auto engine = make_unique(_seed); + m_urd = make_shared(std::move(engine)); m_state = make_shared(m_urd); } @@ -1299,6 +1300,5 @@ string SolidityGenerator::generateTestProgram() [&](auto const& _item) { return _item->setup(); } }, g); string program = generator()->generate(); - destroyGenerators(); return program; } diff --git a/test/tools/ossfuzz/SolidityGenerator.h b/test/tools/ossfuzz/SolidityGenerator.h index ea01e0db6..ae3a40bbe 100644 --- a/test/tools/ossfuzz/SolidityGenerator.h +++ b/test/tools/ossfuzz/SolidityGenerator.h @@ -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; 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 _function) { @@ -517,22 +525,24 @@ struct TestState /// @name currentSourceUnitPath. void addSourceUnit(std::string const& _path) { - sourceUnitState.emplace(_path, std::make_shared(uRandDist, _path)); + auto sourceState = std::make_shared(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(uRandDist, _name)); - sourceUnitState[currentSourceUnitPath]->exports[ - std::make_shared(_name) - ] = _name; + auto newContractState = std::make_shared(uRandDist, _name); + contractState.emplace(_name, std::move(newContractState)); + auto newContractType = std::make_shared(_name); + sourceUnitState[currentSourceUnitPath]->exports[std::move(newContractType)] = _name; currentContract = _name; } void addFunction(std::string const& _name, bool _freeFunction) { - functionState.emplace(_name, std::make_shared(_name, _freeFunction)); + auto fState = std::make_shared(_name, _freeFunction); + functionState.emplace(_name, std::move(fState)); currentFunction = _name; } std::shared_ptr 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 _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 _state): state(std::move(_state)) {} + + ~LiteralGenerator() + { + state.reset(); + } + std::string operator()(std::shared_ptr const& _type); std::string operator()(std::shared_ptr const& _type); std::string operator()(std::shared_ptr const& _type); @@ -745,6 +767,11 @@ struct ExpressionGenerator ExpressionGenerator(std::shared_ptr _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 + std::shared_ptr generator(); + /// @returns a shared ptr to underlying random + /// number distribution. + std::shared_ptr 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() + { + return m_state; + } +private: + template + void createGenerator() + { + auto generator = std::make_shared(this); + m_generators.insert(std::move(generator)); + } + template + void createGenerators(); + /// Sub generators + std::set m_generators; + /// Shared global test state + std::shared_ptr m_state; + /// Uniform random distribution + std::shared_ptr m_urd; +}; + struct GeneratorBase { - explicit GeneratorBase(std::shared_ptr _mutator); + explicit GeneratorBase(SolidityGenerator* _mutator); template std::shared_ptr generator() { @@ -863,7 +935,7 @@ struct GeneratorBase /// this grammar element. void addGenerators(std::set> _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 uRandDist() + { + return mutator->uniformRandomDist(); + } + /// Shared pointer to the mutator instance - std::shared_ptr mutator; + SolidityGenerator* mutator; /// Set of generators used by this generator. std::set> generators; /// Shared ptr to global test state. std::shared_ptr state; - /// Uniform random distribution - std::shared_ptr uRandDist; }; class TestCaseGenerator: public GeneratorBase { public: - explicit TestCaseGenerator(std::shared_ptr _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 _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 _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 _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 _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 _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 _mutator): + explicit StatementGenerator(SolidityGenerator* _mutator): GeneratorBase(std::move(_mutator)) {} void setup() override; @@ -1029,7 +1105,7 @@ public: ASSIGNMOD, ASSIGNMAX }; - explicit AssignmentStmtGenerator(std::shared_ptr _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 _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 _mutator): + FunctionCallGenerator(SolidityGenerator* _mutator): GeneratorBase(std::move(_mutator)) {} std::string visit() override; @@ -1108,47 +1184,4 @@ private: std::optional rhs(std::vector> _functionInputTypeNames); std::string callStmt(std::shared_ptr _callee); }; - -class SolidityGenerator: public std::enable_shared_from_this -{ -public: - explicit SolidityGenerator(unsigned _seed); - - /// @returns the generator of type @param T. - template - std::shared_ptr generator(); - /// @returns a shared ptr to underlying random - /// number distribution. - std::shared_ptr 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() - { - return m_state; - } -private: - template - void createGenerator() - { - m_generators.insert( - std::make_shared(shared_from_this()) - ); - } - template - void createGenerators(); - void destroyGenerators() - { - m_generators.clear(); - } - /// Sub generators - std::set m_generators; - /// Shared global test state - std::shared_ptr m_state; - /// Uniform random distribution - std::shared_ptr m_urd; -}; }