Add utility functions and add/remove store stmt mutator

This commit is contained in:
Bhargava Shastry 2020-01-04 16:27:13 +01:00
parent c954e18e12
commit 8c9c5b74ae
2 changed files with 147 additions and 15 deletions

View File

@ -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<UnaryOp*>(_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<Block*>(_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<StoreFunc_Storage>{}.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<Block*>(_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<FunctionCall_Returns>(
_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<FunctionCall_Returns>{}.enumFromSeed(_seed);
_call->set_ret(type);
_call->set_func_index(_seed);
// Configuration rules:

View File

@ -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<class T> 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 <typename T>
struct EnumTypeConverter
{
T enumFromSeed(unsigned _seed)
{
// TODO: Assert validity of return enum.
return static_cast<T>(_seed % (enumMax() + 1) + enumMin());
}
static int enumMax()
{
if constexpr (std::is_same_v<std::decay_t<T>, FunctionCall_Returns>)
return FunctionCall_Returns_Returns_MAX;
else if constexpr (std::is_same_v<std::decay_t<T>, StoreFunc_Storage>)
return StoreFunc_Storage_Storage_MAX;
else
static_assert(AlwaysFalse<T>::value, "Yul proto mutator: non-exhaustive visitor.");
}
static int enumMin()
{
if constexpr (std::is_same_v<std::decay_t<T>, FunctionCall_Returns>)
return FunctionCall_Returns_Returns_MIN;
else if constexpr (std::is_same_v<std::decay_t<T>, StoreFunc_Storage>)
return StoreFunc_Storage_Storage_MIN;
else
static_assert(AlwaysFalse<T>::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;
};
}
}
}