Merge pull request #10967 from ethereum/proto-mutator

Proto mutator: Add control flow to basic blocks
This commit is contained in:
Bhargava Shastry 2021-02-23 12:03:52 +01:00 committed by GitHub
commit c9f1b55073
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 134 additions and 0 deletions

View File

@ -46,6 +46,34 @@ static LPMPostProcessor<Block> addStoreToZero(
}
);
namespace
{
template <typename T>
struct addControlFlow
{
addControlFlow()
{
function = [](T* _message, unsigned)
{
MutationInfo m{_message, "Added control flow."};
YPM::addControlFlow(_message);
};
/// Unused variable registers callback.
LPMPostProcessor<T> callback(function);
}
function<void(T*, unsigned)> function;
};
}
static addControlFlow<ForStmt> c1;
static addControlFlow<BoundedForStmt> c2;
static addControlFlow<IfStmt> c3;
static addControlFlow<SwitchStmt> c4;
static addControlFlow<FunctionDef> c5;
static addControlFlow<CaseStmt> c6;
static addControlFlow<Code> c7;
Literal* YPM::intLiteral(unsigned _value)
{
auto lit = new Literal();
@ -145,3 +173,100 @@ unsigned YPM::EnumTypeConverter<T>::enumMin()
else
static_assert(AlwaysFalse<T>::value, "Yul proto mutator: non-exhaustive visitor.");
}
template <typename T>
void YPM::addControlFlow(T* _msg)
{
enum class ControlFlowStmt: unsigned
{
For = 0,
BoundedFor,
If,
Switch,
FunctionCall,
Break,
Continue,
Leave,
Termination
};
uniform_int_distribution<unsigned> d(
static_cast<unsigned>(ControlFlowStmt::For),
static_cast<unsigned>(ControlFlowStmt::Termination)
);
auto random = static_cast<ControlFlowStmt>(d(s_rand.m_random));
Statement* s = basicBlock(_msg)->add_statements();
switch (random)
{
case ControlFlowStmt::For:
s->set_allocated_forstmt(new ForStmt());
break;
case ControlFlowStmt::BoundedFor:
s->set_allocated_boundedforstmt(new BoundedForStmt());
break;
case ControlFlowStmt::If:
s->set_allocated_ifstmt(new IfStmt());
break;
case ControlFlowStmt::Switch:
s->set_allocated_switchstmt(new SwitchStmt());
break;
case ControlFlowStmt::FunctionCall:
s->set_allocated_functioncall(new FunctionCall());
break;
case ControlFlowStmt::Break:
s->set_allocated_breakstmt(new BreakStmt());
break;
case ControlFlowStmt::Continue:
s->set_allocated_contstmt(new ContinueStmt());
break;
case ControlFlowStmt::Leave:
s->set_allocated_leave(new LeaveStmt());
break;
case ControlFlowStmt::Termination:
s->set_allocated_terminatestmt(new TerminatingStmt());
break;
}
}
Block* YPM::randomBlock(ForStmt* _stmt)
{
enum class ForBlocks: unsigned
{
Init = 0,
Post = 1,
Body = 2
};
uniform_int_distribution<unsigned> d(
static_cast<unsigned>(ForBlocks::Init),
static_cast<unsigned>(ForBlocks::Body)
);
switch (static_cast<ForBlocks>(d(s_rand.m_random)))
{
case ForBlocks::Init:
return _stmt->mutable_for_init();
case ForBlocks::Post:
return _stmt->mutable_for_post();
case ForBlocks::Body:
return _stmt->mutable_for_body();
}
}
template <typename T>
Block* YPM::basicBlock(T* _msg)
{
if constexpr (std::is_same_v<T, ForStmt>)
return randomBlock(_msg);
else if constexpr (std::is_same_v<T, BoundedForStmt>)
return _msg->mutable_for_body();
else if constexpr (std::is_same_v<T, SwitchStmt>)
return _msg->mutable_default_block();
else if constexpr (std::is_same_v<T, FunctionDef>)
return _msg->mutable_block();
else if constexpr (std::is_same_v<T, IfStmt>)
return _msg->mutable_if_body();
else if constexpr (std::is_same_v<T, CaseStmt>)
return _msg->mutable_case_block();
else if constexpr (std::is_same_v<T, Code>)
return _msg->mutable_block();
else
static_assert(AlwaysFalse<T>::value, "Yul proto mutator: non-exhaustive visitor.");
}

View File

@ -94,5 +94,14 @@ struct YulProtoMutator
static constexpr unsigned s_mediumIP = 29;
/// Modulo for mutations that should occur often
static constexpr unsigned s_highIP = 23;
/// Add control-flow statement to basic block.
template <typename T>
static void addControlFlow(T* _msg);
/// Obtain basic block for statement type.
template <typename T>
static Block* basicBlock(T* _msg);
/// Obtain a basic block in a for stmt uniformly
/// at random
static Block* randomBlock(ForStmt* _msg);
};
}