From 8c9c5b74aea723d30da454241342b85020d35480 Mon Sep 17 00:00:00 2001 From: Bhargava Shastry Date: Sat, 4 Jan 2020 16:27:13 +0100 Subject: [PATCH] Add utility functions and add/remove store stmt mutator --- .../ossfuzz/protomutators/YulProtoMutator.cpp | 107 ++++++++++++++++-- .../ossfuzz/protomutators/YulProtoMutator.h | 55 +++++++-- 2 files changed, 147 insertions(+), 15 deletions(-) diff --git a/test/tools/ossfuzz/protomutators/YulProtoMutator.cpp b/test/tools/ossfuzz/protomutators/YulProtoMutator.cpp index ffe88da99..325944a4b 100644 --- a/test/tools/ossfuzz/protomutators/YulProtoMutator.cpp +++ b/test/tools/ossfuzz/protomutators/YulProtoMutator.cpp @@ -220,6 +220,86 @@ static YulProtoMutator addMloadZero( } ); +/// Remove unary operation mload(0) +static YulProtoMutator removeMloadZero( + UnaryOp::descriptor(), + [](google::protobuf::Message* _message, unsigned int _seed) + { + auto unaryOp = static_cast(_message); + if (_seed % YulProtoMutator::s_mediumIP == 1) + { + if (unaryOp->has_op() == UnaryOp::MLOAD) + { +#ifdef DEBUG + std::cout << "----------------------------------" << std::endl; + std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; + std::cout << "YULMUTATOR: Remove mload" << std::endl; +#endif + unaryOp->clear_op(); + unaryOp->clear_operand(); +#ifdef DEBUG + std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; + std::cout << "----------------------------------" << std::endl; +#endif + } + } + } +); + +/// Add m/sstore(0, variable) +static YulProtoMutator addStoreToZero( + Block::descriptor(), + [](google::protobuf::Message* _message, unsigned int _seed) + { + auto block = static_cast(_message); + if (_seed % YulProtoMutator::s_mediumIP == 0) + { +#ifdef DEBUG + std::cout << "----------------------------------" << std::endl; + std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; + std::cout << "YULMUTATOR: store added" << std::endl; +#endif + auto storeStmt = new StoreFunc(); + storeStmt->set_st(YulProtoMutator::EnumTypeConverter{}.enumFromSeed(_seed)); + storeStmt->set_allocated_loc(YulProtoMutator::litExpression(0)); + storeStmt->set_allocated_loc(YulProtoMutator::refExpression(_seed)); + auto stmt = block->add_statements(); + stmt->set_allocated_storage_func(storeStmt); +#ifdef DEBUG + std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; + std::cout << "----------------------------------" << std::endl; +#endif + } + } +); + +/// Remove m/sstore(0, ref) +static YulProtoMutator removeStore( + Block::descriptor(), + [](google::protobuf::Message* _message, unsigned int _seed) + { + auto block = static_cast(_message); + if (_seed % YulProtoMutator::s_mediumIP == 1) + { +#ifdef DEBUG + std::cout << "----------------------------------" << std::endl; + std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; + std::cout << "YULMUTATOR: Remove store" << std::endl; +#endif + for (auto &stmt: *block->mutable_statements()) + if (stmt.has_storage_func()) + { + stmt.clear_storage_func(); + break; + } +#ifdef DEBUG + std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; + std::cout << "----------------------------------" << std::endl; +#endif + } + } +); + /// Invert condition of a for statement static YulProtoMutator invertForCondition( ForStmt::descriptor(), @@ -674,6 +754,10 @@ static YulProtoMutator addFuncDef( auto funcDef = new FunctionDef(); funcDef->set_num_input_params(_seed); funcDef->set_num_output_params(_seed + block->ByteSizeLong()); + // Copy block into function body + auto funcBlock = new Block(); + funcBlock->CopyFrom(*block); + funcDef->set_allocated_block(funcBlock); stmt->set_allocated_funcdef(funcDef); #ifdef DEBUG std::cout << protobuf_mutator::SaveMessageAsText(*_message) << std::endl; @@ -809,28 +893,37 @@ static YulProtoMutator removeGenericFor( Literal* YulProtoMutator::intLiteral(unsigned _value) { - Literal *lit = new Literal(); + auto lit = new Literal(); lit->set_intval(_value); return lit; } +Expression* YulProtoMutator::litExpression(unsigned _value) +{ + auto lit = intLiteral(_value); + auto expr = new Expression(); + expr->set_allocated_cons(lit); + return expr; +} + VarRef* YulProtoMutator::varRef(unsigned _seed) { - VarRef *varref = new VarRef(); + auto varref = new VarRef(); varref->set_varnum(_seed); return varref; } -FunctionCall_Returns YulProtoMutator::callType(unsigned _seed) +Expression* YulProtoMutator::refExpression(unsigned _seed) { - return static_cast( - _seed % FunctionCall_Returns_Returns_ARRAYSIZE + FunctionCall_Returns_Returns_MIN - ); + auto ref = varRef(_seed); + auto refExpr = new Expression(); + refExpr->set_allocated_varref(ref); + return refExpr; } void YulProtoMutator::configureCall(FunctionCall *_call, unsigned int _seed) { - auto type = callType(_seed); + auto type = EnumTypeConverter{}.enumFromSeed(_seed); _call->set_ret(type); _call->set_func_index(_seed); // Configuration rules: diff --git a/test/tools/ossfuzz/protomutators/YulProtoMutator.h b/test/tools/ossfuzz/protomutators/YulProtoMutator.h index 5764d96a2..e68d266cd 100644 --- a/test/tools/ossfuzz/protomutators/YulProtoMutator.h +++ b/test/tools/ossfuzz/protomutators/YulProtoMutator.h @@ -25,26 +25,65 @@ struct YulProtoMutator static Literal* intLiteral(unsigned _value); /// Return a variable reference - /// @param _seed: Pseudo-random unsigned integer used to reference - /// an existing variable. + /// @param _seed: Pseudo-random unsigned integer used as index + /// of variable to be referenced static VarRef* varRef(unsigned _seed); - /// Return a valid function call type from a pseudo-random seed. - /// @param _seed: Pseudo-random unsigned integer - static FunctionCall_Returns callType(unsigned _seed); + /// Return a literal expression + /// @param _value: value of literal expression + static Expression* litExpression(unsigned _value); + + /// Return a reference expression + /// @param _seed: Pseudo-random unsigned integer used as index + /// of variable to be referenced + static Expression* refExpression(unsigned _seed); /// Configure function call from a pseudo-random seed. /// @param _call: Pre-allocated FunctionCall protobuf message /// @param _seed: Pseudo-random unsigned integer static void configureCall(FunctionCall *_call, unsigned _seed); + /// Helper type for type matching visitor. + template struct AlwaysFalse: std::false_type {}; + + /// Template struct for obtaining a valid enum value of + /// template type from pseudo-random unsigned integer. + /// @param _seed: Pseudo-random integer + /// @returns Valid enum of template enum type + template + struct EnumTypeConverter + { + T enumFromSeed(unsigned _seed) + { + // TODO: Assert validity of return enum. + return static_cast(_seed % (enumMax() + 1) + enumMin()); + } + + static int enumMax() + { + if constexpr (std::is_same_v, FunctionCall_Returns>) + return FunctionCall_Returns_Returns_MAX; + else if constexpr (std::is_same_v, StoreFunc_Storage>) + return StoreFunc_Storage_Storage_MAX; + else + static_assert(AlwaysFalse::value, "Yul proto mutator: non-exhaustive visitor."); + } + + static int enumMin() + { + if constexpr (std::is_same_v, FunctionCall_Returns>) + return FunctionCall_Returns_Returns_MIN; + else if constexpr (std::is_same_v, StoreFunc_Storage>) + return StoreFunc_Storage_Storage_MIN; + else + static_assert(AlwaysFalse::value, "Yul proto mutator: non-exhaustive visitor."); + } + }; + static constexpr unsigned s_lowIP = 827; static constexpr unsigned s_mediumIP = 569; static constexpr unsigned s_highIP = 251; }; - - - } } } \ No newline at end of file