mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10967 from ethereum/proto-mutator
Proto mutator: Add control flow to basic blocks
This commit is contained in:
commit
c9f1b55073
@ -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)
|
Literal* YPM::intLiteral(unsigned _value)
|
||||||
{
|
{
|
||||||
auto lit = new Literal();
|
auto lit = new Literal();
|
||||||
@ -145,3 +173,100 @@ unsigned YPM::EnumTypeConverter<T>::enumMin()
|
|||||||
else
|
else
|
||||||
static_assert(AlwaysFalse<T>::value, "Yul proto mutator: non-exhaustive visitor.");
|
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.");
|
||||||
|
}
|
||||||
|
@ -94,5 +94,14 @@ struct YulProtoMutator
|
|||||||
static constexpr unsigned s_mediumIP = 29;
|
static constexpr unsigned s_mediumIP = 29;
|
||||||
/// Modulo for mutations that should occur often
|
/// Modulo for mutations that should occur often
|
||||||
static constexpr unsigned s_highIP = 23;
|
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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user