mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #12958 from ethereum/yul-fuzzer-bound-memory-accesses
Yul grammar generator: Bound memory accesses.
This commit is contained in:
commit
665bf29a84
@ -6,8 +6,8 @@
|
|||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Trace:
|
// Trace:
|
||||||
// CREATE(0, 0xffffffffffffffffffffffffffffffffffffffff, 0)
|
// CREATE(0, 0, 0)
|
||||||
// CREATE(0, 0xffffffffffffffffffffffffffffffffffffffff, 0)
|
// CREATE(0, 0, 0)
|
||||||
// Memory dump:
|
// Memory dump:
|
||||||
// 0: 0000000000000000000000000000000000000000000000000000000000000001
|
// 0: 0000000000000000000000000000000000000000000000000000000000000001
|
||||||
// Storage dump:
|
// Storage dump:
|
||||||
|
@ -8,8 +8,8 @@
|
|||||||
// EVMVersion: >=constantinople
|
// EVMVersion: >=constantinople
|
||||||
// ----
|
// ----
|
||||||
// Trace:
|
// Trace:
|
||||||
// CREATE2(0, 0xffffffffffffffffffffffffffffffffffffffff, 0, 0)
|
// CREATE2(0, 0, 0, 0)
|
||||||
// CREATE2(0, 0xffffffffffffffffffffffffffffffffffffffff, 0, 0)
|
// CREATE2(0, 0, 0, 0)
|
||||||
// Memory dump:
|
// Memory dump:
|
||||||
// 0: 0000000000000000000000000000000000000000000000000000000000000001
|
// 0: 0000000000000000000000000000000000000000000000000000000000000001
|
||||||
// Storage dump:
|
// Storage dump:
|
||||||
|
40
test/libyul/yulInterpreterTests/zero_length_reads.yul
Normal file
40
test/libyul/yulInterpreterTests/zero_length_reads.yul
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
returndatacopy(1, 1, 0)
|
||||||
|
calldatacopy(1, 1, 0)
|
||||||
|
extcodecopy(1, 1, 1, 0)
|
||||||
|
codecopy(1, 1, 0)
|
||||||
|
log0(1, 0)
|
||||||
|
log1(1, 0, 1)
|
||||||
|
log2(1, 0, 1, 1)
|
||||||
|
log3(1, 0, 1, 1, 1)
|
||||||
|
log4(1, 0, 1, 1, 1, 1)
|
||||||
|
pop(create(1, 1, 0))
|
||||||
|
pop(create2(1, 1, 0, 1))
|
||||||
|
pop(call(1, 1, 1, 1, 0, 1, 0))
|
||||||
|
pop(callcode(1, 1, 1, 1, 0, 1, 0))
|
||||||
|
pop(delegatecall(1, 1, 1, 0, 1, 0))
|
||||||
|
pop(staticcall(1, 1, 1, 0, 1, 0))
|
||||||
|
return(1, 0)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=constantinople
|
||||||
|
// ----
|
||||||
|
// Trace:
|
||||||
|
// RETURNDATACOPY(0, 1, 0)
|
||||||
|
// CALLDATACOPY(0, 1, 0)
|
||||||
|
// EXTCODECOPY(1, 0, 1, 0)
|
||||||
|
// CODECOPY(0, 1, 0)
|
||||||
|
// LOG0(0, 0)
|
||||||
|
// LOG1(0, 0, 1)
|
||||||
|
// LOG2(0, 0, 1, 1)
|
||||||
|
// LOG3(0, 0, 1, 1, 1)
|
||||||
|
// LOG4(0, 0, 1, 1, 1, 1)
|
||||||
|
// CREATE(1, 0, 0)
|
||||||
|
// CREATE2(1, 0, 0, 1)
|
||||||
|
// CALL(1, 1, 1, 0, 0, 1, 0)
|
||||||
|
// CALLCODE(1, 1, 1, 0, 0, 1, 0)
|
||||||
|
// DELEGATECALL(1, 1, 0, 0, 1, 0)
|
||||||
|
// STATICCALL(1, 1, 0, 0, 1, 0)
|
||||||
|
// RETURN(0, 0)
|
||||||
|
// Memory dump:
|
||||||
|
// Storage dump:
|
@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
returndatacopy(1, 1, 0)
|
||||||
|
calldatacopy(1, 1, 0)
|
||||||
|
extcodecopy(1, 1, 1, 0)
|
||||||
|
codecopy(1, 1, 0)
|
||||||
|
log0(1, 0)
|
||||||
|
log1(1, 0, 1)
|
||||||
|
log2(1, 0, 1, 1)
|
||||||
|
log3(1, 0, 1, 1, 1)
|
||||||
|
log4(1, 0, 1, 1, 1, 1)
|
||||||
|
pop(create(1, 1, 0))
|
||||||
|
pop(create2(1, 1, 0, 1))
|
||||||
|
pop(call(1, 1, 1, 1, 0, 1, 0))
|
||||||
|
pop(callcode(1, 1, 1, 1, 0, 1, 0))
|
||||||
|
pop(delegatecall(1, 1, 1, 0, 1, 0))
|
||||||
|
pop(staticcall(1, 1, 1, 0, 1, 0))
|
||||||
|
revert(1, 0)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=constantinople
|
||||||
|
// ----
|
||||||
|
// Trace:
|
||||||
|
// RETURNDATACOPY(0, 1, 0)
|
||||||
|
// CALLDATACOPY(0, 1, 0)
|
||||||
|
// EXTCODECOPY(1, 0, 1, 0)
|
||||||
|
// CODECOPY(0, 1, 0)
|
||||||
|
// LOG0(0, 0)
|
||||||
|
// LOG1(0, 0, 1)
|
||||||
|
// LOG2(0, 0, 1, 1)
|
||||||
|
// LOG3(0, 0, 1, 1, 1)
|
||||||
|
// LOG4(0, 0, 1, 1, 1, 1)
|
||||||
|
// CREATE(1, 0, 0)
|
||||||
|
// CREATE2(1, 0, 0, 1)
|
||||||
|
// CALL(1, 1, 1, 0, 0, 1, 0)
|
||||||
|
// CALLCODE(1, 1, 1, 0, 0, 1, 0)
|
||||||
|
// DELEGATECALL(1, 1, 0, 0, 1, 0)
|
||||||
|
// STATICCALL(1, 1, 0, 0, 1, 0)
|
||||||
|
// REVERT(0, 0)
|
||||||
|
// Memory dump:
|
||||||
|
// Storage dump:
|
@ -5,6 +5,6 @@
|
|||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Trace:
|
// Trace:
|
||||||
// CALLDATACOPY(32, 0, 0)
|
// CALLDATACOPY(0, 0, 0)
|
||||||
// Memory dump:
|
// Memory dump:
|
||||||
// Storage dump:
|
// Storage dump:
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
returndatacopy(1, 1, 0)
|
||||||
|
calldatacopy(1, 1, 0)
|
||||||
|
extcodecopy(1, 1, 1, 0)
|
||||||
|
codecopy(1, 1, 0)
|
||||||
|
log0(1, 0)
|
||||||
|
log1(1, 0, 1)
|
||||||
|
log2(1, 0, 1, 1)
|
||||||
|
log3(1, 0, 1, 1, 1)
|
||||||
|
log4(1, 0, 1, 1, 1, 1)
|
||||||
|
pop(create(1, 1, 0))
|
||||||
|
pop(create2(1, 1, 0, 1))
|
||||||
|
pop(call(1, 1, 1, 1, 0, 1, 0))
|
||||||
|
pop(callcode(1, 1, 1, 1, 0, 1, 0))
|
||||||
|
pop(delegatecall(1, 1, 1, 0, 1, 0))
|
||||||
|
pop(staticcall(1, 1, 1, 0, 1, 0))
|
||||||
|
return(1, 0)
|
||||||
|
}
|
||||||
|
// ====
|
||||||
|
// EVMVersion: >=constantinople
|
||||||
|
// ----
|
||||||
|
// step: loadResolver
|
||||||
|
//
|
||||||
|
// {
|
||||||
|
// {
|
||||||
|
// let _1 := 0
|
||||||
|
// let _2 := 1
|
||||||
|
// returndatacopy(0, _2, _1)
|
||||||
|
// calldatacopy(0, _2, _1)
|
||||||
|
// extcodecopy(_2, 0, _2, _1)
|
||||||
|
// codecopy(0, _2, _1)
|
||||||
|
// log0(0, _1)
|
||||||
|
// log1(0, _1, _2)
|
||||||
|
// log2(0, _1, _2, _2)
|
||||||
|
// log3(0, _1, _2, _2, _2)
|
||||||
|
// log4(0, _1, _2, _2, _2, _2)
|
||||||
|
// pop(create(_2, 0, _1))
|
||||||
|
// pop(create2(_2, 0, _1, _2))
|
||||||
|
// pop(call(_2, _2, _2, 0, _1, _2, _1))
|
||||||
|
// pop(callcode(_2, _2, _2, 0, _1, _2, _1))
|
||||||
|
// pop(delegatecall(_2, _2, 0, _1, _2, _1))
|
||||||
|
// pop(staticcall(_2, _2, 0, _1, _2, _1))
|
||||||
|
// return(0, _1)
|
||||||
|
// }
|
||||||
|
// }
|
@ -351,9 +351,22 @@ void ProtoConverter::visit(BinaryOp const& _x)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
|
if (op == BinaryOp::KECCAK)
|
||||||
|
{
|
||||||
|
m_output << "mod(";
|
||||||
|
visit(_x.left());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
|
m_output << ",";
|
||||||
|
m_output << "mod(";
|
||||||
|
visit(_x.right());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
visit(_x.left());
|
visit(_x.left());
|
||||||
m_output << ",";
|
m_output << ",";
|
||||||
visit(_x.right());
|
visit(_x.right());
|
||||||
|
}
|
||||||
m_output << ")";
|
m_output << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -623,6 +636,13 @@ void ProtoConverter::visit(UnaryOp const& _x)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
|
if (op == UnaryOp::MLOAD)
|
||||||
|
{
|
||||||
|
m_output << "mod(";
|
||||||
|
visit(_x.operand());
|
||||||
|
m_output << ", " << to_string(s_maxMemory) << ")";
|
||||||
|
}
|
||||||
|
else
|
||||||
visit(_x.operand());
|
visit(_x.operand());
|
||||||
m_output << ")";
|
m_output << ")";
|
||||||
}
|
}
|
||||||
@ -778,11 +798,15 @@ void ProtoConverter::visit(CopyFunc const& _x)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.target());
|
visit(_x.target());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.source());
|
visit(_x.source());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.size());
|
visit(_x.size());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -792,32 +816,42 @@ void ProtoConverter::visit(ExtCodeCopy const& _x)
|
|||||||
m_output << "(";
|
m_output << "(";
|
||||||
visit(_x.addr());
|
visit(_x.addr());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.target());
|
visit(_x.target());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.source());
|
visit(_x.source());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.size());
|
visit(_x.size());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProtoConverter::visit(LogFunc const& _x)
|
void ProtoConverter::visit(LogFunc const& _x)
|
||||||
{
|
{
|
||||||
|
auto visitPosAndSize = [&](LogFunc const& _y) {
|
||||||
|
m_output << "mod(";
|
||||||
|
visit(_y.pos());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
|
visit(_y.size());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
|
};
|
||||||
|
|
||||||
switch (_x.num_topics())
|
switch (_x.num_topics())
|
||||||
{
|
{
|
||||||
case LogFunc::ZERO:
|
case LogFunc::ZERO:
|
||||||
m_output << "log0";
|
m_output << "log0";
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
visit(_x.pos());
|
visitPosAndSize(_x);
|
||||||
m_output << ", ";
|
|
||||||
visit(_x.size());
|
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
break;
|
break;
|
||||||
case LogFunc::ONE:
|
case LogFunc::ONE:
|
||||||
m_output << "log1";
|
m_output << "log1";
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
visit(_x.pos());
|
visitPosAndSize(_x);
|
||||||
m_output << ", ";
|
|
||||||
visit(_x.size());
|
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.t1());
|
visit(_x.t1());
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
@ -825,9 +859,7 @@ void ProtoConverter::visit(LogFunc const& _x)
|
|||||||
case LogFunc::TWO:
|
case LogFunc::TWO:
|
||||||
m_output << "log2";
|
m_output << "log2";
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
visit(_x.pos());
|
visitPosAndSize(_x);
|
||||||
m_output << ", ";
|
|
||||||
visit(_x.size());
|
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.t1());
|
visit(_x.t1());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
@ -837,9 +869,7 @@ void ProtoConverter::visit(LogFunc const& _x)
|
|||||||
case LogFunc::THREE:
|
case LogFunc::THREE:
|
||||||
m_output << "log3";
|
m_output << "log3";
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
visit(_x.pos());
|
visitPosAndSize(_x);
|
||||||
m_output << ", ";
|
|
||||||
visit(_x.size());
|
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.t1());
|
visit(_x.t1());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
@ -851,9 +881,7 @@ void ProtoConverter::visit(LogFunc const& _x)
|
|||||||
case LogFunc::FOUR:
|
case LogFunc::FOUR:
|
||||||
m_output << "log4";
|
m_output << "log4";
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
visit(_x.pos());
|
visitPosAndSize(_x);
|
||||||
m_output << ", ";
|
|
||||||
visit(_x.size());
|
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.t1());
|
visit(_x.t1());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
@ -1015,13 +1043,21 @@ void ProtoConverter::visit(LowLevelCall const& _x)
|
|||||||
visit(_x.wei());
|
visit(_x.wei());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
}
|
}
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.in());
|
visit(_x.in());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.insize());
|
visit(_x.insize());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.out());
|
visit(_x.out());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.outsize());
|
visit(_x.outsize());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
m_output << ")";
|
m_output << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1048,9 +1084,13 @@ void ProtoConverter::visit(Create const& _x)
|
|||||||
}
|
}
|
||||||
visit(_x.wei());
|
visit(_x.wei());
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.position());
|
visit(_x.position());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.size());
|
visit(_x.size());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
if (type == Create::CREATE2)
|
if (type == Create::CREATE2)
|
||||||
{
|
{
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
@ -1069,7 +1109,8 @@ void ProtoConverter::visit(IfStmt const& _x)
|
|||||||
|
|
||||||
void ProtoConverter::visit(StoreFunc const& _x)
|
void ProtoConverter::visit(StoreFunc const& _x)
|
||||||
{
|
{
|
||||||
switch (_x.st())
|
auto storeType = _x.st();
|
||||||
|
switch (storeType)
|
||||||
{
|
{
|
||||||
case StoreFunc::MSTORE:
|
case StoreFunc::MSTORE:
|
||||||
m_output << "mstore(";
|
m_output << "mstore(";
|
||||||
@ -1081,7 +1122,15 @@ void ProtoConverter::visit(StoreFunc const& _x)
|
|||||||
m_output << "mstore8(";
|
m_output << "mstore8(";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// Write to memory within bounds, storage is unbounded
|
||||||
|
if (storeType == StoreFunc::SSTORE)
|
||||||
visit(_x.loc());
|
visit(_x.loc());
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_output << "mod(";
|
||||||
|
visit(_x.loc());
|
||||||
|
m_output << ", " << to_string(s_maxMemory) << ")";
|
||||||
|
}
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
visit(_x.val());
|
visit(_x.val());
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
@ -1262,9 +1311,13 @@ void ProtoConverter::visit(RetRevStmt const& _x)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
m_output << "(";
|
m_output << "(";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.pos());
|
visit(_x.pos());
|
||||||
|
m_output << ", " << to_string(s_maxMemory - s_maxSize) << ")";
|
||||||
m_output << ", ";
|
m_output << ", ";
|
||||||
|
m_output << "mod(";
|
||||||
visit(_x.size());
|
visit(_x.size());
|
||||||
|
m_output << ", " << to_string(s_maxSize) << ")";
|
||||||
m_output << ")\n";
|
m_output << ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1651,8 +1704,12 @@ void ProtoConverter::fillFunctionCallInput(unsigned _numInParams)
|
|||||||
m_output << "calldataload(" << slot << ")";
|
m_output << "calldataload(" << slot << ")";
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
{
|
||||||
|
// Access memory within stipulated bounds
|
||||||
|
slot = "mod(" + dictionaryToken() + ", " + to_string(s_maxMemory) + ")";
|
||||||
m_output << "mload(" << slot << ")";
|
m_output << "mload(" << slot << ")";
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 2:
|
case 2:
|
||||||
m_output << "sload(" << slot << ")";
|
m_output << "sload(" << slot << ")";
|
||||||
break;
|
break;
|
||||||
|
@ -344,6 +344,11 @@ private:
|
|||||||
static unsigned constexpr s_modOutputParams = 5;
|
static unsigned constexpr s_modOutputParams = 5;
|
||||||
/// Hard-coded identifier for a Yul object's data block
|
/// Hard-coded identifier for a Yul object's data block
|
||||||
static auto constexpr s_dataIdentifier = "datablock";
|
static auto constexpr s_dataIdentifier = "datablock";
|
||||||
|
/// Upper bound on memory writes = 2**32 - 1
|
||||||
|
/// See: https://eips.ethereum.org/EIPS/eip-1985#memory-size
|
||||||
|
static unsigned constexpr s_maxMemory = 4294967295;
|
||||||
|
/// Upper bound on size for range copy functions
|
||||||
|
static unsigned constexpr s_maxSize = 65536;
|
||||||
/// Predicate to keep track of for body scope. If false, break/continue
|
/// Predicate to keep track of for body scope. If false, break/continue
|
||||||
/// statements can not be created.
|
/// statements can not be created.
|
||||||
bool m_inForBodyScope;
|
bool m_inForBodyScope;
|
||||||
|
@ -211,22 +211,22 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::CALLDATASIZE:
|
case Instruction::CALLDATASIZE:
|
||||||
return m_state.calldata.size();
|
return m_state.calldata.size();
|
||||||
case Instruction::CALLDATACOPY:
|
case Instruction::CALLDATACOPY:
|
||||||
logTrace(_instruction, arg);
|
|
||||||
if (accessMemory(arg[0], arg[2]))
|
if (accessMemory(arg[0], arg[2]))
|
||||||
copyZeroExtended(
|
copyZeroExtended(
|
||||||
m_state.memory, m_state.calldata,
|
m_state.memory, m_state.calldata,
|
||||||
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
||||||
);
|
);
|
||||||
|
logTrace(_instruction, arg);
|
||||||
return 0;
|
return 0;
|
||||||
case Instruction::CODESIZE:
|
case Instruction::CODESIZE:
|
||||||
return m_state.code.size();
|
return m_state.code.size();
|
||||||
case Instruction::CODECOPY:
|
case Instruction::CODECOPY:
|
||||||
logTrace(_instruction, arg);
|
|
||||||
if (accessMemory(arg[0], arg[2]))
|
if (accessMemory(arg[0], arg[2]))
|
||||||
copyZeroExtended(
|
copyZeroExtended(
|
||||||
m_state.memory, m_state.code,
|
m_state.memory, m_state.code,
|
||||||
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
||||||
);
|
);
|
||||||
|
logTrace(_instruction, arg);
|
||||||
return 0;
|
return 0;
|
||||||
case Instruction::GASPRICE:
|
case Instruction::GASPRICE:
|
||||||
return m_state.gasprice;
|
return m_state.gasprice;
|
||||||
@ -239,23 +239,23 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::EXTCODEHASH:
|
case Instruction::EXTCODEHASH:
|
||||||
return u256(keccak256(h256(arg[0] + 1)));
|
return u256(keccak256(h256(arg[0] + 1)));
|
||||||
case Instruction::EXTCODECOPY:
|
case Instruction::EXTCODECOPY:
|
||||||
logTrace(_instruction, arg);
|
|
||||||
if (accessMemory(arg[1], arg[3]))
|
if (accessMemory(arg[1], arg[3]))
|
||||||
// TODO this way extcodecopy and codecopy do the same thing.
|
// TODO this way extcodecopy and codecopy do the same thing.
|
||||||
copyZeroExtended(
|
copyZeroExtended(
|
||||||
m_state.memory, m_state.code,
|
m_state.memory, m_state.code,
|
||||||
size_t(arg[1]), size_t(arg[2]), size_t(arg[3])
|
size_t(arg[1]), size_t(arg[2]), size_t(arg[3])
|
||||||
);
|
);
|
||||||
|
logTrace(_instruction, arg);
|
||||||
return 0;
|
return 0;
|
||||||
case Instruction::RETURNDATASIZE:
|
case Instruction::RETURNDATASIZE:
|
||||||
return m_state.returndata.size();
|
return m_state.returndata.size();
|
||||||
case Instruction::RETURNDATACOPY:
|
case Instruction::RETURNDATACOPY:
|
||||||
logTrace(_instruction, arg);
|
|
||||||
if (accessMemory(arg[0], arg[2]))
|
if (accessMemory(arg[0], arg[2]))
|
||||||
copyZeroExtended(
|
copyZeroExtended(
|
||||||
m_state.memory, m_state.returndata,
|
m_state.memory, m_state.returndata,
|
||||||
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
size_t(arg[0]), size_t(arg[1]), size_t(arg[2])
|
||||||
);
|
);
|
||||||
|
logTrace(_instruction, arg);
|
||||||
return 0;
|
return 0;
|
||||||
case Instruction::BLOCKHASH:
|
case Instruction::BLOCKHASH:
|
||||||
if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber)
|
if (arg[0] >= m_state.blockNumber || arg[0] + 256 < m_state.blockNumber)
|
||||||
@ -319,11 +319,17 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
case Instruction::CREATE:
|
case Instruction::CREATE:
|
||||||
accessMemory(arg[1], arg[2]);
|
accessMemory(arg[1], arg[2]);
|
||||||
logTrace(_instruction, arg);
|
logTrace(_instruction, arg);
|
||||||
|
if (arg[2] != 0)
|
||||||
return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff");
|
return (0xcccccc + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
else
|
||||||
|
return 0xcccccc;
|
||||||
case Instruction::CREATE2:
|
case Instruction::CREATE2:
|
||||||
accessMemory(arg[1], arg[2]);
|
accessMemory(arg[1], arg[2]);
|
||||||
logTrace(_instruction, arg);
|
logTrace(_instruction, arg);
|
||||||
|
if (arg[2] != 0)
|
||||||
return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff");
|
return (0xdddddd + arg[1]) & u256("0xffffffffffffffffffffffffffffffffffffffff");
|
||||||
|
else
|
||||||
|
return 0xdddddd;
|
||||||
case Instruction::CALL:
|
case Instruction::CALL:
|
||||||
case Instruction::CALLCODE:
|
case Instruction::CALLCODE:
|
||||||
accessMemory(arg[3], arg[4]);
|
accessMemory(arg[3], arg[4]);
|
||||||
@ -340,7 +346,6 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
accessMemory(arg[2], arg[3]);
|
accessMemory(arg[2], arg[3]);
|
||||||
accessMemory(arg[4], arg[5]);
|
accessMemory(arg[4], arg[5]);
|
||||||
logTrace(_instruction, arg);
|
logTrace(_instruction, arg);
|
||||||
|
|
||||||
// Randomly fail based on the called address if it isn't a call to self.
|
// Randomly fail based on the called address if it isn't a call to self.
|
||||||
// Used for fuzzing.
|
// Used for fuzzing.
|
||||||
return (
|
return (
|
||||||
@ -359,7 +364,6 @@ u256 EVMInstructionInterpreter::eval(
|
|||||||
accessMemory(arg[0], arg[1]);
|
accessMemory(arg[0], arg[1]);
|
||||||
logTrace(_instruction, arg);
|
logTrace(_instruction, arg);
|
||||||
m_state.storage.clear();
|
m_state.storage.clear();
|
||||||
m_state.trace.clear();
|
|
||||||
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
BOOST_THROW_EXCEPTION(ExplicitlyTerminated());
|
||||||
case Instruction::INVALID:
|
case Instruction::INVALID:
|
||||||
logTrace(_instruction);
|
logTrace(_instruction);
|
||||||
@ -479,7 +483,10 @@ u256 EVMInstructionInterpreter::evalBuiltin(
|
|||||||
else if (fun == "datacopy")
|
else if (fun == "datacopy")
|
||||||
{
|
{
|
||||||
// This is identical to codecopy.
|
// This is identical to codecopy.
|
||||||
if (accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2)))
|
if (
|
||||||
|
_evaluatedArguments.at(2) != 0 &&
|
||||||
|
accessMemory(_evaluatedArguments.at(0), _evaluatedArguments.at(2))
|
||||||
|
)
|
||||||
copyZeroExtended(
|
copyZeroExtended(
|
||||||
m_state.memory,
|
m_state.memory,
|
||||||
m_state.code,
|
m_state.code,
|
||||||
@ -560,8 +567,13 @@ void EVMInstructionInterpreter::logTrace(
|
|||||||
if (!(_writesToMemory && memWriteTracingDisabled()))
|
if (!(_writesToMemory && memWriteTracingDisabled()))
|
||||||
{
|
{
|
||||||
string message = _pseudoInstruction + "(";
|
string message = _pseudoInstruction + "(";
|
||||||
|
std::pair<bool, size_t> inputMemoryPtrModified = isInputMemoryPtrModified(_pseudoInstruction, _arguments);
|
||||||
for (size_t i = 0; i < _arguments.size(); ++i)
|
for (size_t i = 0; i < _arguments.size(); ++i)
|
||||||
message += (i > 0 ? ", " : "") + formatNumber(_arguments[i]);
|
{
|
||||||
|
bool printZero = inputMemoryPtrModified.first && inputMemoryPtrModified.second == i;
|
||||||
|
u256 arg = printZero ? 0 : _arguments[i];
|
||||||
|
message += (i > 0 ? ", " : "") + formatNumber(arg);
|
||||||
|
}
|
||||||
message += ")";
|
message += ")";
|
||||||
if (!_data.empty())
|
if (!_data.empty())
|
||||||
message += " [" + util::toHex(_data) + "]";
|
message += " [" + util::toHex(_data) + "]";
|
||||||
@ -573,3 +585,65 @@ void EVMInstructionInterpreter::logTrace(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<bool, size_t> EVMInstructionInterpreter::isInputMemoryPtrModified(
|
||||||
|
std::string const& _pseudoInstruction,
|
||||||
|
std::vector<u256> const& _arguments
|
||||||
|
)
|
||||||
|
{
|
||||||
|
if (_pseudoInstruction == "RETURN" || _pseudoInstruction == "REVERT")
|
||||||
|
{
|
||||||
|
if (_arguments[1] == 0)
|
||||||
|
return {true, 0};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
_pseudoInstruction == "RETURNDATACOPY" || _pseudoInstruction == "CALLDATACOPY"
|
||||||
|
|| _pseudoInstruction == "CODECOPY")
|
||||||
|
{
|
||||||
|
if (_arguments[2] == 0)
|
||||||
|
return {true, 0};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
else if (_pseudoInstruction == "EXTCODECOPY")
|
||||||
|
{
|
||||||
|
if (_arguments[3] == 0)
|
||||||
|
return {true, 1};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
else if (
|
||||||
|
_pseudoInstruction == "LOG0" || _pseudoInstruction == "LOG1" || _pseudoInstruction == "LOG2"
|
||||||
|
|| _pseudoInstruction == "LOG3" || _pseudoInstruction == "LOG4")
|
||||||
|
{
|
||||||
|
if (_arguments[1] == 0)
|
||||||
|
return {true, 0};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
if (_pseudoInstruction == "CREATE" || _pseudoInstruction == "CREATE2")
|
||||||
|
{
|
||||||
|
if (_arguments[2] == 0)
|
||||||
|
return {true, 1};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
if (_pseudoInstruction == "CALL" || _pseudoInstruction == "CALLCODE")
|
||||||
|
{
|
||||||
|
if (_arguments[4] == 0)
|
||||||
|
return {true, 3};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
else if (_pseudoInstruction == "DELEGATECALL" || _pseudoInstruction == "STATICCALL")
|
||||||
|
{
|
||||||
|
if (_arguments[3] == 0)
|
||||||
|
return {true, 2};
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return {false, 0};
|
||||||
|
}
|
||||||
|
@ -125,6 +125,19 @@ private:
|
|||||||
std::vector<u256> const& _arguments = {},
|
std::vector<u256> const& _arguments = {},
|
||||||
bytes const& _data = {}
|
bytes const& _data = {}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// @returns a pair of boolean and size_t whose first value is true if @param _pseudoInstruction
|
||||||
|
/// is a Yul instruction that the Yul optimizer's loadResolver step rewrites the input
|
||||||
|
/// memory pointer value to zero if that instruction's read length (contained within @param
|
||||||
|
// _arguments) is zero, and whose second value is the positional index of the input memory
|
||||||
|
// pointer argument.
|
||||||
|
/// If the Yul instruction is unaffected or affected but read length is non-zero, the first
|
||||||
|
/// value is false.
|
||||||
|
std::pair<bool, size_t> isInputMemoryPtrModified(
|
||||||
|
std::string const& _pseudoInstruction,
|
||||||
|
std::vector<u256> const& _arguments
|
||||||
|
);
|
||||||
|
|
||||||
/// @returns disable trace flag.
|
/// @returns disable trace flag.
|
||||||
bool memWriteTracingDisabled()
|
bool memWriteTracingDisabled()
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user