From 67644c0763e7dbdc7fbb7cafccac3b9e3929b770 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Mon, 7 Jun 2021 18:45:34 +0200 Subject: [PATCH] Introduce break/continue statements and fix stmt genarator logic --- test/tools/ossfuzz/Generators.h | 2 + test/tools/ossfuzz/SolidityGenerator.cpp | 40 ++++++++--------- test/tools/ossfuzz/SolidityGenerator.h | 57 +++++++++++++++++++++++- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/test/tools/ossfuzz/Generators.h b/test/tools/ossfuzz/Generators.h index 56dcfdc99..bd7c4b1b0 100644 --- a/test/tools/ossfuzz/Generators.h +++ b/test/tools/ossfuzz/Generators.h @@ -43,6 +43,8 @@ #define GENERATORLIST(MACRO, SEP, ENDSEP) \ MACRO(AssignmentStmtGenerator) SEP \ MACRO(BlockStmtGenerator) SEP \ + MACRO(BreakStmtGenerator) SEP \ + MACRO(ContinueStmtGenerator) SEP \ MACRO(ContractGenerator) SEP \ MACRO(ExpressionStmtGenerator) SEP \ MACRO(FunctionCallGenerator) SEP \ diff --git a/test/tools/ossfuzz/SolidityGenerator.cpp b/test/tools/ossfuzz/SolidityGenerator.cpp index ac466380c..e7ccf0cbc 100644 --- a/test/tools/ossfuzz/SolidityGenerator.cpp +++ b/test/tools/ossfuzz/SolidityGenerator.cpp @@ -511,6 +511,8 @@ void WhileStmtGenerator::setup() string WhileStmtGenerator::visit() { ostringstream whileStmt; + state->enterLoop(); + ScopeGuard exitLoop([&]() { state->exitLoop(); }); ExpressionGenerator exprGen{state}; auto boolType = make_shared(); pair boolTypeName = {boolType, {}}; @@ -538,7 +540,9 @@ void StatementGenerator::setup() {mutator->generator(), 1}, {mutator->generator(), 1}, {mutator->generator(), 2}, - {mutator->generator(), 1} + {mutator->generator(), 1}, + {mutator->generator(), 1}, + {mutator->generator(), 1} }; addGenerators(std::move(dependsOn)); } @@ -553,25 +557,21 @@ string StatementGenerator::visit() mutator->generator()->unchecked(true); ostringstream os; - // Randomise visit order - vector> randomisedChildren; - for (auto const& child: generators) - randomisedChildren.push_back(child); - shuffle(randomisedChildren.begin(), randomisedChildren.end(), *uRandDist()->randomEngine); - for (auto const& child: randomisedChildren) - if (uRandDist()->likely(child.second + 1)) - { - os << std::visit(GenericVisitor{ - [](auto const& _item) { return _item->generate(); } - }, child.first); - if (holds_alternative>(child.first) && - generateUncheckedBlock - ) - { - get>(child.first)->unchecked(false); - get>(child.first)->resetInUnchecked(); - } - } + // Choose random statement type + auto genIterator = generators.begin(); + auto advanceBy = uRandDist()->distributionOneToN(generators.size()) - 1; + std::advance(genIterator, advanceBy); + auto child = *genIterator; + os << std::visit(GenericVisitor{ + [](auto const& _item) { return _item->generate(); } + }, child.first); + if (holds_alternative>(child.first) && + generateUncheckedBlock + ) + { + get>(child.first)->unchecked(false); + get>(child.first)->resetInUnchecked(); + } return os.str(); } diff --git a/test/tools/ossfuzz/SolidityGenerator.h b/test/tools/ossfuzz/SolidityGenerator.h index 33964ee1f..6323ada3c 100644 --- a/test/tools/ossfuzz/SolidityGenerator.h +++ b/test/tools/ossfuzz/SolidityGenerator.h @@ -504,6 +504,13 @@ struct ContractState std::string name; }; +struct LoopState +{ + explicit LoopState(bool _inLoop, bool _wasLoop): inLoop(_inLoop), wasLoop(_wasLoop) {} + bool inLoop; + bool wasLoop; +}; + struct TestState { explicit TestState(std::shared_ptr& _urd): @@ -517,7 +524,8 @@ struct TestState numContracts(0), numFunctions(0), indentationLevel(0), - insideContract(false) + insideContract(false), + loopState(false, false) {} /// Adds @param _path to @name sourceUnitPaths updates /// @name currentSourceUnitPath. @@ -642,6 +650,19 @@ struct TestState { insideContract = false; } + void enterLoop() + { + loopState.wasLoop = loopState.inLoop; + loopState.inLoop = true; + } + void exitLoop() + { + loopState.inLoop = loopState.wasLoop; + } + bool inLoop() + { + return loopState.inLoop; + } ~TestState() { sourceUnitState.clear(); @@ -681,6 +702,8 @@ struct TestState unsigned indentationLevel; /// Contract scope bool insideContract; + /// Loop state + LoopState loopState; /// Source name prefix std::string const sourceUnitNamePrefix = "su"; /// Contract name prefix @@ -1096,6 +1119,38 @@ private: static constexpr size_t s_maxConditionalStmts = 5; }; +class BreakStmtGenerator: public GeneratorBase +{ +public: + explicit BreakStmtGenerator(SolidityGenerator* _mutator): + GeneratorBase(std::move(_mutator)) + {} + std::string visit() override + { + if (state->inLoop()) + return indentation() + "break;\n"; + else + return "\n"; + } + std::string name() override { return "Break statement generator"; } +}; + +class ContinueStmtGenerator: public GeneratorBase +{ +public: + explicit ContinueStmtGenerator(SolidityGenerator* _mutator): + GeneratorBase(std::move(_mutator)) + {} + std::string visit() override + { + if (state->inLoop()) + return indentation() + "continue;\n"; + else + return "\n"; + } + std::string name() override { return "Continue statement generator"; } +}; + class WhileStmtGenerator: public GeneratorBase { public: