mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
yul proto fuzzer: Add EVM version field
This commit is contained in:
parent
45caaf5ad8
commit
a335fed189
@ -30,6 +30,7 @@
|
|||||||
using namespace std;
|
using namespace std;
|
||||||
using namespace solidity::yul::test::yul_fuzzer;
|
using namespace solidity::yul::test::yul_fuzzer;
|
||||||
using namespace solidity::yul::test;
|
using namespace solidity::yul::test;
|
||||||
|
using namespace solidity::langutil;
|
||||||
using namespace solidity::util;
|
using namespace solidity::util;
|
||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
|
|
||||||
@ -86,6 +87,29 @@ string ProtoConverter::createAlphaNum(string const& _strBytes)
|
|||||||
return tmp;
|
return tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EVMVersion ProtoConverter::evmVersionMapping(Program_Version const& _ver)
|
||||||
|
{
|
||||||
|
switch (_ver)
|
||||||
|
{
|
||||||
|
case Program::HOMESTEAD:
|
||||||
|
return EVMVersion::homestead();
|
||||||
|
case Program::TANGERINE:
|
||||||
|
return EVMVersion::tangerineWhistle();
|
||||||
|
case Program::SPURIOUS:
|
||||||
|
return EVMVersion::spuriousDragon();
|
||||||
|
case Program::BYZANTIUM:
|
||||||
|
return EVMVersion::byzantium();
|
||||||
|
case Program::CONSTANTINOPLE:
|
||||||
|
return EVMVersion::constantinople();
|
||||||
|
case Program::PETERSBURG:
|
||||||
|
return EVMVersion::petersburg();
|
||||||
|
case Program::ISTANBUL:
|
||||||
|
return EVMVersion::istanbul();
|
||||||
|
case Program::BERLIN:
|
||||||
|
return EVMVersion::berlin();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string ProtoConverter::visit(Literal const& _x)
|
string ProtoConverter::visit(Literal const& _x)
|
||||||
{
|
{
|
||||||
switch (_x.literal_oneof_case())
|
switch (_x.literal_oneof_case())
|
||||||
@ -230,7 +254,16 @@ void ProtoConverter::visit(Expression const& _x)
|
|||||||
|
|
||||||
void ProtoConverter::visit(BinaryOp const& _x)
|
void ProtoConverter::visit(BinaryOp const& _x)
|
||||||
{
|
{
|
||||||
switch (_x.op())
|
BinaryOp_BOp op = _x.op();
|
||||||
|
|
||||||
|
if ((op == BinaryOp::SHL || op == BinaryOp::SHR || op == BinaryOp::SAR) &&
|
||||||
|
!m_evmVersion.hasBitwiseShifting())
|
||||||
|
{
|
||||||
|
m_output << dictionaryToken();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (op)
|
||||||
{
|
{
|
||||||
case BinaryOp::ADD:
|
case BinaryOp::ADD:
|
||||||
m_output << "add";
|
m_output << "add";
|
||||||
@ -266,12 +299,15 @@ void ProtoConverter::visit(BinaryOp const& _x)
|
|||||||
m_output << "gt";
|
m_output << "gt";
|
||||||
break;
|
break;
|
||||||
case BinaryOp::SHR:
|
case BinaryOp::SHR:
|
||||||
|
yulAssert(m_evmVersion.hasBitwiseShifting(), "Proto fuzzer: Invalid evm version");
|
||||||
m_output << "shr";
|
m_output << "shr";
|
||||||
break;
|
break;
|
||||||
case BinaryOp::SHL:
|
case BinaryOp::SHL:
|
||||||
|
yulAssert(m_evmVersion.hasBitwiseShifting(), "Proto fuzzer: Invalid evm version");
|
||||||
m_output << "shl";
|
m_output << "shl";
|
||||||
break;
|
break;
|
||||||
case BinaryOp::SAR:
|
case BinaryOp::SAR:
|
||||||
|
yulAssert(m_evmVersion.hasBitwiseShifting(), "Proto fuzzer: Invalid evm version");
|
||||||
m_output << "sar";
|
m_output << "sar";
|
||||||
break;
|
break;
|
||||||
case BinaryOp::SDIV:
|
case BinaryOp::SDIV:
|
||||||
@ -475,7 +511,17 @@ void ProtoConverter::visit(TypedVarDecl const& _x)
|
|||||||
|
|
||||||
void ProtoConverter::visit(UnaryOp const& _x)
|
void ProtoConverter::visit(UnaryOp const& _x)
|
||||||
{
|
{
|
||||||
switch (_x.op())
|
UnaryOp_UOp op = _x.op();
|
||||||
|
|
||||||
|
// Replace calls to extcodehash on unsupported EVMs with a dictionary
|
||||||
|
// token.
|
||||||
|
if (op == UnaryOp::EXTCODEHASH && !m_evmVersion.hasExtCodeHash())
|
||||||
|
{
|
||||||
|
m_output << dictionaryToken();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (op)
|
||||||
{
|
{
|
||||||
case UnaryOp::NOT:
|
case UnaryOp::NOT:
|
||||||
m_output << "not";
|
m_output << "not";
|
||||||
@ -550,7 +596,12 @@ void ProtoConverter::visit(NullaryOp const& _x)
|
|||||||
m_output << "codesize()";
|
m_output << "codesize()";
|
||||||
break;
|
break;
|
||||||
case NullaryOp::RETURNDATASIZE:
|
case NullaryOp::RETURNDATASIZE:
|
||||||
|
// If evm supports returndatasize, we generate it. Otherwise,
|
||||||
|
// we output a dictionary token.
|
||||||
|
if (m_evmVersion.supportsReturndata())
|
||||||
m_output << "returndatasize()";
|
m_output << "returndatasize()";
|
||||||
|
else
|
||||||
|
m_output << dictionaryToken();
|
||||||
break;
|
break;
|
||||||
case NullaryOp::ADDRESS:
|
case NullaryOp::ADDRESS:
|
||||||
m_output << "address()";
|
m_output << "address()";
|
||||||
@ -583,10 +634,20 @@ void ProtoConverter::visit(NullaryOp const& _x)
|
|||||||
m_output << "gaslimit()";
|
m_output << "gaslimit()";
|
||||||
break;
|
break;
|
||||||
case NullaryOp::SELFBALANCE:
|
case NullaryOp::SELFBALANCE:
|
||||||
|
// Replace calls to selfbalance() on unsupported EVMs with a dictionary
|
||||||
|
// token.
|
||||||
|
if (m_evmVersion.hasSelfBalance())
|
||||||
m_output << "selfbalance()";
|
m_output << "selfbalance()";
|
||||||
|
else
|
||||||
|
m_output << dictionaryToken();
|
||||||
break;
|
break;
|
||||||
case NullaryOp::CHAINID:
|
case NullaryOp::CHAINID:
|
||||||
|
// Replace calls to chainid() on unsupported EVMs with a dictionary
|
||||||
|
// token.
|
||||||
|
if (m_evmVersion.hasChainID())
|
||||||
m_output << "chainid()";
|
m_output << "chainid()";
|
||||||
|
else
|
||||||
|
m_output << dictionaryToken();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -600,6 +661,11 @@ void ProtoConverter::visit(CopyFunc const& _x)
|
|||||||
if (type == CopyFunc::DATA && !m_isObject)
|
if (type == CopyFunc::DATA && !m_isObject)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// We don't generate code if the copy function is returndatacopy
|
||||||
|
// and the underlying evm does not support it.
|
||||||
|
if (type == CopyFunc::RETURNDATA && !m_evmVersion.supportsReturndata())
|
||||||
|
return;
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case CopyFunc::CALLDATA:
|
case CopyFunc::CALLDATA:
|
||||||
@ -609,6 +675,7 @@ void ProtoConverter::visit(CopyFunc const& _x)
|
|||||||
m_output << "codecopy";
|
m_output << "codecopy";
|
||||||
break;
|
break;
|
||||||
case CopyFunc::RETURNDATA:
|
case CopyFunc::RETURNDATA:
|
||||||
|
yulAssert(m_evmVersion.supportsReturndata(), "Proto fuzzer: Invalid evm version");
|
||||||
m_output << "returndatacopy";
|
m_output << "returndatacopy";
|
||||||
break;
|
break;
|
||||||
case CopyFunc::DATA:
|
case CopyFunc::DATA:
|
||||||
@ -890,6 +957,16 @@ void ProtoConverter::visit(FunctionCall const& _x)
|
|||||||
void ProtoConverter::visit(LowLevelCall const& _x)
|
void ProtoConverter::visit(LowLevelCall const& _x)
|
||||||
{
|
{
|
||||||
LowLevelCall_Type type = _x.callty();
|
LowLevelCall_Type type = _x.callty();
|
||||||
|
|
||||||
|
// Generate staticcall if it is supported by the underlying evm
|
||||||
|
if (type == LowLevelCall::STATICCALL && !m_evmVersion.hasStaticCall())
|
||||||
|
{
|
||||||
|
// Since staticcall is supposed to return 0 on success and 1 on
|
||||||
|
// failure, we can use counter value to emulate it
|
||||||
|
m_output << ((counter() % 2) ? "0" : "1");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case LowLevelCall::CALL:
|
case LowLevelCall::CALL:
|
||||||
@ -902,6 +979,7 @@ void ProtoConverter::visit(LowLevelCall const& _x)
|
|||||||
m_output << "delegatecall(";
|
m_output << "delegatecall(";
|
||||||
break;
|
break;
|
||||||
case LowLevelCall::STATICCALL:
|
case LowLevelCall::STATICCALL:
|
||||||
|
yulAssert(m_evmVersion.hasStaticCall(), "Proto fuzzer: Invalid evm version");
|
||||||
m_output << "staticcall(";
|
m_output << "staticcall(";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -927,6 +1005,15 @@ void ProtoConverter::visit(LowLevelCall const& _x)
|
|||||||
void ProtoConverter::visit(Create const& _x)
|
void ProtoConverter::visit(Create const& _x)
|
||||||
{
|
{
|
||||||
Create_Type type = _x.createty();
|
Create_Type type = _x.createty();
|
||||||
|
|
||||||
|
// Replace a call to create2 on unsupported EVMs with a dictionary
|
||||||
|
// token.
|
||||||
|
if (type == Create::CREATE2 && !m_evmVersion.hasCreate2())
|
||||||
|
{
|
||||||
|
m_output << dictionaryToken();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
case Create::CREATE:
|
case Create::CREATE:
|
||||||
@ -1737,6 +1824,9 @@ void ProtoConverter::visit(Program const& _x)
|
|||||||
// Initialize input size
|
// Initialize input size
|
||||||
m_inputSize = _x.ByteSizeLong();
|
m_inputSize = _x.ByteSizeLong();
|
||||||
|
|
||||||
|
// Record EVM Version
|
||||||
|
m_evmVersion = evmVersionMapping(_x.ver());
|
||||||
|
|
||||||
// Program is either a yul object or a block of
|
// Program is either a yul object or a block of
|
||||||
// statements.
|
// statements.
|
||||||
switch (_x.program_oneof_case())
|
switch (_x.program_oneof_case())
|
||||||
|
@ -31,6 +31,8 @@
|
|||||||
#include <libsolutil/FixedHash.h>
|
#include <libsolutil/FixedHash.h>
|
||||||
#include <libsolutil/Whiskers.h>
|
#include <libsolutil/Whiskers.h>
|
||||||
|
|
||||||
|
#include <liblangutil/EVMVersion.h>
|
||||||
|
|
||||||
namespace solidity::yul::test::yul_fuzzer
|
namespace solidity::yul::test::yul_fuzzer
|
||||||
{
|
{
|
||||||
class ProtoConverter
|
class ProtoConverter
|
||||||
@ -56,6 +58,12 @@ public:
|
|||||||
ProtoConverter(ProtoConverter&&) = delete;
|
ProtoConverter(ProtoConverter&&) = delete;
|
||||||
std::string programToString(Program const& _input);
|
std::string programToString(Program const& _input);
|
||||||
|
|
||||||
|
/// Returns evm version
|
||||||
|
solidity::langutil::EVMVersion version()
|
||||||
|
{
|
||||||
|
return m_evmVersion;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void visit(BinaryOp const&);
|
void visit(BinaryOp const&);
|
||||||
|
|
||||||
@ -270,6 +278,10 @@ private:
|
|||||||
/// dictionarySize is the total number of entries in the dictionary.
|
/// dictionarySize is the total number of entries in the dictionary.
|
||||||
std::string dictionaryToken(util::HexPrefix _p = util::HexPrefix::Add);
|
std::string dictionaryToken(util::HexPrefix _p = util::HexPrefix::Add);
|
||||||
|
|
||||||
|
/// Returns an EVMVersion object corresponding to the protobuf
|
||||||
|
/// enum of type Program_Version
|
||||||
|
solidity::langutil::EVMVersion evmVersionMapping(Program_Version const& _x);
|
||||||
|
|
||||||
/// Returns a monotonically increasing counter that starts from zero.
|
/// Returns a monotonically increasing counter that starts from zero.
|
||||||
unsigned counter()
|
unsigned counter()
|
||||||
{
|
{
|
||||||
@ -367,5 +379,7 @@ private:
|
|||||||
/// Flag to track whether scope extension of variables defined in for-init
|
/// Flag to track whether scope extension of variables defined in for-init
|
||||||
/// block is enabled.
|
/// block is enabled.
|
||||||
bool m_forInitScopeExtEnabled;
|
bool m_forInitScopeExtEnabled;
|
||||||
|
/// Object that holds the targeted evm version specified by protobuf input
|
||||||
|
solidity::langutil::EVMVersion m_evmVersion;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -405,10 +405,21 @@ message Data {
|
|||||||
}
|
}
|
||||||
|
|
||||||
message Program {
|
message Program {
|
||||||
|
enum Version {
|
||||||
|
HOMESTEAD = 0;
|
||||||
|
TANGERINE = 1;
|
||||||
|
SPURIOUS = 2;
|
||||||
|
BYZANTIUM = 3;
|
||||||
|
CONSTANTINOPLE = 4;
|
||||||
|
PETERSBURG = 5;
|
||||||
|
ISTANBUL = 6;
|
||||||
|
BERLIN = 7;
|
||||||
|
}
|
||||||
oneof program_oneof {
|
oneof program_oneof {
|
||||||
Block block = 1;
|
Block block = 1;
|
||||||
Object obj = 2;
|
Object obj = 2;
|
||||||
}
|
}
|
||||||
|
required Version ver = 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
package solidity.yul.test.yul_fuzzer;
|
package solidity.yul.test.yul_fuzzer;
|
||||||
|
@ -29,12 +29,14 @@
|
|||||||
using namespace solidity;
|
using namespace solidity;
|
||||||
using namespace solidity::yul;
|
using namespace solidity::yul;
|
||||||
using namespace solidity::yul::test::yul_fuzzer;
|
using namespace solidity::yul::test::yul_fuzzer;
|
||||||
|
using namespace solidity::langutil;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
DEFINE_PROTO_FUZZER(Program const& _input)
|
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||||
{
|
{
|
||||||
ProtoConverter converter;
|
ProtoConverter converter;
|
||||||
string yul_source = converter.programToString(_input);
|
string yul_source = converter.programToString(_input);
|
||||||
|
EVMVersion version = converter.version();
|
||||||
|
|
||||||
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
||||||
{
|
{
|
||||||
@ -51,7 +53,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
|
|
||||||
// AssemblyStack entry point
|
// AssemblyStack entry point
|
||||||
AssemblyStack stack(
|
AssemblyStack stack(
|
||||||
langutil::EVMVersion(),
|
version,
|
||||||
AssemblyStack::Language::StrictAssembly,
|
AssemblyStack::Language::StrictAssembly,
|
||||||
solidity::frontend::OptimiserSettings::full()
|
solidity::frontend::OptimiserSettings::full()
|
||||||
);
|
);
|
||||||
|
@ -55,7 +55,9 @@ void printErrors(ostream& _stream, ErrorList const& _errors)
|
|||||||
|
|
||||||
DEFINE_PROTO_FUZZER(Program const& _input)
|
DEFINE_PROTO_FUZZER(Program const& _input)
|
||||||
{
|
{
|
||||||
string yul_source = ProtoConverter().programToString(_input);
|
ProtoConverter converter;
|
||||||
|
string yul_source = converter.programToString(_input);
|
||||||
|
EVMVersion version = converter.version();
|
||||||
|
|
||||||
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
if (const char* dump_path = getenv("PROTO_FUZZER_DUMP_PATH"))
|
||||||
{
|
{
|
||||||
@ -69,7 +71,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
|
|
||||||
// AssemblyStack entry point
|
// AssemblyStack entry point
|
||||||
AssemblyStack stack(
|
AssemblyStack stack(
|
||||||
langutil::EVMVersion::berlin(),
|
version,
|
||||||
AssemblyStack::Language::StrictAssembly,
|
AssemblyStack::Language::StrictAssembly,
|
||||||
solidity::frontend::OptimiserSettings::full()
|
solidity::frontend::OptimiserSettings::full()
|
||||||
);
|
);
|
||||||
@ -87,7 +89,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret(
|
yulFuzzerUtil::TerminationReason termReason = yulFuzzerUtil::interpret(
|
||||||
os1,
|
os1,
|
||||||
stack.parserResult()->code,
|
stack.parserResult()->code,
|
||||||
EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion::berlin())
|
EVMDialect::strictAssemblyForEVMObjects(version)
|
||||||
);
|
);
|
||||||
|
|
||||||
if (termReason == yulFuzzerUtil::TerminationReason::StepLimitReached)
|
if (termReason == yulFuzzerUtil::TerminationReason::StepLimitReached)
|
||||||
@ -97,7 +99,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
|
|||||||
termReason = yulFuzzerUtil::interpret(
|
termReason = yulFuzzerUtil::interpret(
|
||||||
os2,
|
os2,
|
||||||
stack.parserResult()->code,
|
stack.parserResult()->code,
|
||||||
EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion::berlin()),
|
EVMDialect::strictAssemblyForEVMObjects(version),
|
||||||
(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 4)
|
(yul::test::yul_fuzzer::yulFuzzerUtil::maxSteps * 4)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user