mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #7326 from ethereum/develop
Merge develop into 0.6.0 branch.
This commit is contained in:
commit
c499758cd8
@ -494,6 +494,7 @@ jobs:
|
||||
environment:
|
||||
EVM: constantinople
|
||||
OPTIMIZE: 0
|
||||
flags: --no-smt
|
||||
ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2
|
||||
|
||||
t_ems_solcjs:
|
||||
|
31
.clang-format
Normal file
31
.clang-format
Normal file
@ -0,0 +1,31 @@
|
||||
# Formatting approximately used in Solidity's C++
|
||||
#
|
||||
# See https://clang.llvm.org/docs/ClangFormatStyleOptions.html
|
||||
# For an online formatter to test settings, see
|
||||
# https://zed0.co.uk/clang-format-configurator/
|
||||
# Note that clang-format cannot express the style that closing parentheses
|
||||
# behave similar to closing curly braces in a multi-line setting in that
|
||||
# they have to be on a line of their own at the same indentation level
|
||||
# as the opening part.
|
||||
|
||||
Language: Cpp
|
||||
BasedOnStyle: LLVM
|
||||
AlignEscapedNewlinesLeft: true
|
||||
AlwaysBreakAfterReturnType: None
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: All
|
||||
BreakBeforeBraces: Allman
|
||||
ColumnLimit: 120
|
||||
ContinuationIndentWidth: 4
|
||||
IndentWidth: 4
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MaxEmptyLinesToKeep: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 2000
|
||||
SpaceAfterCStyleCast: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
TabWidth: 4
|
||||
|
||||
# Local Variables:
|
||||
# mode: yaml
|
||||
# End:
|
@ -21,6 +21,7 @@ Language Features:
|
||||
|
||||
|
||||
Compiler Features:
|
||||
* Optimizer: Add rule that replaces the BYTE opcode by 0 if the first argument is larger than 31.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -41,15 +41,11 @@ become the new richest.
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function becomeRichest() public payable returns (bool) {
|
||||
if (msg.value > mostSent) {
|
||||
pendingWithdrawals[richest] += msg.value;
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
function becomeRichest() public payable {
|
||||
require(msg.value > mostSent, "Not enough money sent.");
|
||||
pendingWithdrawals[richest] += msg.value;
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function withdraw() public {
|
||||
@ -76,16 +72,12 @@ This is as opposed to the more intuitive sending pattern:
|
||||
mostSent = msg.value;
|
||||
}
|
||||
|
||||
function becomeRichest() public payable returns (bool) {
|
||||
if (msg.value > mostSent) {
|
||||
// This line can cause problems (explained below).
|
||||
richest.transfer(msg.value);
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
function becomeRichest() public payable {
|
||||
require(msg.value > mostSent, "Not enough money sent.");
|
||||
// This line can cause problems (explained below).
|
||||
richest.transfer(msg.value);
|
||||
richest = msg.sender;
|
||||
mostSent = msg.value;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -259,6 +259,14 @@ std::vector<SimplificationRule<Pattern>> simplificationRuleListPart5(
|
||||
[=]() { return A.d() >= 256; }
|
||||
});
|
||||
|
||||
// Replace BYTE(A, X), A >= 32 with 0
|
||||
rules.push_back({
|
||||
{Instruction::BYTE, {A, X}},
|
||||
[=]() -> Pattern { return u256(0); },
|
||||
true,
|
||||
[=]() { return A.d() >= 32; }
|
||||
});
|
||||
|
||||
for (auto const& op: std::vector<Instruction>{
|
||||
Instruction::ADDRESS,
|
||||
Instruction::CALLER,
|
||||
|
@ -748,6 +748,12 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_indexAccess.indexExpression())
|
||||
{
|
||||
solAssert(_indexAccess.annotation().type->category() == Type::Category::TypeType, "");
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(array, "");
|
||||
defineExpr(_indexAccess, smt::Expression::select(
|
||||
array->currentValue(),
|
||||
|
@ -51,7 +51,7 @@ parts:
|
||||
source: https://github.com/CVC4/CVC4.git
|
||||
source-tag: "1.7"
|
||||
plugin: nil
|
||||
build-packages: [python, cmake, openjdk-11-jre, libgmp-dev]
|
||||
build-packages: [python, cmake, openjdk-11-jre, libgmp-dev, wget]
|
||||
override-build: |
|
||||
./contrib/get-antlr-3.4
|
||||
./configure.sh --prefix=$SNAPCRAFT_STAGE/usr
|
||||
|
@ -2,7 +2,7 @@
|
||||
"extends": "solhint:default",
|
||||
"plugins": [],
|
||||
"rules": {
|
||||
"compiler-fixed": false,
|
||||
"no-inline-assembly": false
|
||||
"compiler-fixed": "off",
|
||||
"no-inline-assembly": "off"
|
||||
}
|
||||
}
|
@ -1,10 +1,19 @@
|
||||
contract C {
|
||||
function e() public {
|
||||
function e() public pure {
|
||||
revert("Transaction failed.");
|
||||
}
|
||||
function f(bool _value) public pure {
|
||||
string memory message;
|
||||
require(_value, message);
|
||||
}
|
||||
function g(bool _value) public pure {
|
||||
require(_value, "Value is false.");
|
||||
}
|
||||
}
|
||||
// ====
|
||||
// EVMVersion: >homestead
|
||||
// ----
|
||||
// _() -> FAILURE
|
||||
// e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed."
|
||||
// f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0
|
||||
// g(bool): false -> FAILURE, hex"08c379a0", 0x20, 15, "Value is false."
|
||||
|
@ -0,0 +1,11 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
|
||||
function f() public pure { int[][]; }
|
||||
|
||||
}
|
||||
// ----
|
||||
// Warning: (73-80): Statement has no effect.
|
||||
// Warning: (73-78): Assertion checker does not yet implement type type(int256[] memory)
|
||||
// Warning: (73-78): Assertion checker does not yet implement this expression.
|
||||
// Warning: (73-80): Assertion checker does not yet implement type type(int256[] memory[] memory)
|
@ -0,0 +1,12 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
|
||||
function f() public pure { int[][][]; }
|
||||
|
||||
}
|
||||
// ----
|
||||
// Warning: (73-82): Statement has no effect.
|
||||
// Warning: (73-78): Assertion checker does not yet implement type type(int256[] memory)
|
||||
// Warning: (73-78): Assertion checker does not yet implement this expression.
|
||||
// Warning: (73-80): Assertion checker does not yet implement type type(int256[] memory[] memory)
|
||||
// Warning: (73-82): Assertion checker does not yet implement type type(int256[] memory[] memory[] memory)
|
@ -0,0 +1,12 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
|
||||
function f() public pure { (int[][]); }
|
||||
|
||||
}
|
||||
// ----
|
||||
// Warning: (73-82): Statement has no effect.
|
||||
// Warning: (74-79): Assertion checker does not yet implement type type(int256[] memory)
|
||||
// Warning: (74-79): Assertion checker does not yet implement this expression.
|
||||
// Warning: (74-81): Assertion checker does not yet implement type type(int256[] memory[] memory)
|
||||
// Warning: (73-82): Assertion checker does not yet implement type type(int256[] memory[] memory)
|
@ -0,0 +1,13 @@
|
||||
pragma experimental SMTChecker;
|
||||
contract C {
|
||||
|
||||
function f() public pure { (int[][][]); }
|
||||
|
||||
}
|
||||
// ----
|
||||
// Warning: (73-84): Statement has no effect.
|
||||
// Warning: (74-79): Assertion checker does not yet implement type type(int256[] memory)
|
||||
// Warning: (74-79): Assertion checker does not yet implement this expression.
|
||||
// Warning: (74-81): Assertion checker does not yet implement type type(int256[] memory[] memory)
|
||||
// Warning: (74-83): Assertion checker does not yet implement type type(int256[] memory[] memory[] memory)
|
||||
// Warning: (73-84): Assertion checker does not yet implement type type(int256[] memory[] memory[] memory)
|
@ -208,7 +208,11 @@ string BytesUtils::formatRawBytes(
|
||||
dev::solidity::test::ParameterList const& _parameters,
|
||||
string _linePrefix)
|
||||
{
|
||||
soltestAssert(_bytes.size() == ContractABIUtils::encodingSize(_parameters), "");
|
||||
soltestAssert(
|
||||
_bytes.size() == ContractABIUtils::encodingSize(_parameters),
|
||||
"Got " + to_string(_bytes.size()) + " bytes, but expected " +
|
||||
to_string(ContractABIUtils::encodingSize(_parameters)) + " bytes."
|
||||
);
|
||||
|
||||
stringstream os;
|
||||
auto it = _bytes.begin();
|
||||
@ -275,7 +279,11 @@ string BytesUtils::formatBytesRange(
|
||||
bool _highlight
|
||||
)
|
||||
{
|
||||
soltestAssert(_bytes.size() == ContractABIUtils::encodingSize(_parameters), "");
|
||||
soltestAssert(
|
||||
_bytes.size() == ContractABIUtils::encodingSize(_parameters),
|
||||
"Got " + to_string(_bytes.size()) + " bytes, but expected " +
|
||||
to_string(ContractABIUtils::encodingSize(_parameters)) + " bytes."
|
||||
);
|
||||
|
||||
stringstream os;
|
||||
auto it = _bytes.begin();
|
||||
|
@ -313,14 +313,18 @@ dev::solidity::test::ParameterList ContractABIUtils::defaultParameters(size_t co
|
||||
return parameters;
|
||||
}
|
||||
|
||||
dev::solidity::test::ParameterList ContractABIUtils::failureParameters()
|
||||
dev::solidity::test::ParameterList ContractABIUtils::failureParameters(bytes const _bytes)
|
||||
{
|
||||
ParameterList parameters;
|
||||
|
||||
parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::HexString, ABIType::AlignNone, 4}, FormatInfo{}});
|
||||
parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::Hex}, FormatInfo{}});
|
||||
parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::UnsignedDec}, FormatInfo{}});
|
||||
parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::String}, FormatInfo{}});
|
||||
|
||||
/// If _bytes contains at least a 1 byte message (function selector + tail pointer + message length + message)
|
||||
/// append an additional string parameter to represent that message.
|
||||
if (_bytes.size() > 68)
|
||||
parameters.push_back(Parameter{bytes(), "", ABIType{ABIType::String}, FormatInfo{}});
|
||||
|
||||
return parameters;
|
||||
}
|
||||
|
@ -66,8 +66,10 @@ public:
|
||||
);
|
||||
|
||||
/// Returns a list of parameters corresponding to the encoding of
|
||||
/// returned values in case of a failure.
|
||||
static ParameterList failureParameters();
|
||||
/// returned values in case of a failure. Creates an additional parameter
|
||||
/// for the error message if _bytes is larger than 68 bytes
|
||||
/// (function_selector + tail_ptr + message_length).
|
||||
static ParameterList failureParameters(bytes const _bytes);
|
||||
|
||||
/// Returns _count parameters with their type set to ABIType::UnsignedDec
|
||||
/// and their size set to 32 bytes.
|
||||
|
@ -127,7 +127,7 @@ string TestFunctionCall::format(
|
||||
boost::optional<ParameterList> abiParams;
|
||||
|
||||
if (isFailure && !output.empty())
|
||||
abiParams = boost::make_optional(ContractABIUtils::failureParameters());
|
||||
abiParams = boost::make_optional(ContractABIUtils::failureParameters(output));
|
||||
else
|
||||
abiParams = ContractABIUtils::parametersFromJsonOutputs(
|
||||
_errorReporter,
|
||||
@ -193,7 +193,7 @@ string TestFunctionCall::formatBytesParameters(
|
||||
{
|
||||
os << BytesUtils::formatBytesRange(
|
||||
_bytes,
|
||||
ContractABIUtils::failureParameters(),
|
||||
ContractABIUtils::failureParameters(_bytes),
|
||||
_highlight
|
||||
);
|
||||
|
||||
|
@ -121,7 +121,6 @@ string YulInterpreterTest::interpret()
|
||||
InterpreterState state;
|
||||
state.maxTraceSize = 10000;
|
||||
state.maxSteps = 10000;
|
||||
state.maxMemSize = 0x20000000;
|
||||
Interpreter interpreter(state, EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}));
|
||||
try
|
||||
{
|
||||
|
20
test/libyul/yulInterpreterTests/function_scopes.yul
Normal file
20
test/libyul/yulInterpreterTests/function_scopes.yul
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
f(1)
|
||||
function f(i) {
|
||||
if i { g(1) }
|
||||
function g(j) {
|
||||
if j { h() }
|
||||
f(0)
|
||||
function h() {
|
||||
g(0)
|
||||
}
|
||||
}
|
||||
sstore(i, add(i, 7))
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// Trace:
|
||||
// Memory dump:
|
||||
// Storage dump:
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000007
|
||||
// 0000000000000000000000000000000000000000000000000000000000000001: 0000000000000000000000000000000000000000000000000000000000000008
|
14
test/libyul/yulInterpreterTests/recursion.yul
Normal file
14
test/libyul/yulInterpreterTests/recursion.yul
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
function fib(i) -> y {
|
||||
y := 1
|
||||
if gt(i, 2) {
|
||||
y := add(fib(sub(i, 1)), fib(sub(i, 2)))
|
||||
}
|
||||
}
|
||||
sstore(0, fib(8))
|
||||
}
|
||||
// ----
|
||||
// Trace:
|
||||
// Memory dump:
|
||||
// Storage dump:
|
||||
// 0000000000000000000000000000000000000000000000000000000000000000: 0000000000000000000000000000000000000000000000000000000000000015
|
@ -0,0 +1,16 @@
|
||||
{
|
||||
let a := calldataload(0)
|
||||
let b := byte(33, a)
|
||||
let c := byte(20, a)
|
||||
// create cannot be removed.
|
||||
let d := byte(33, create(0, 0, 0x20))
|
||||
}
|
||||
// ====
|
||||
// step: expressionSimplifier
|
||||
// ----
|
||||
// {
|
||||
// let a := calldataload(0)
|
||||
// let b := 0
|
||||
// let c := byte(20, a)
|
||||
// let d := byte(33, create(0, 0, 0x20))
|
||||
// }
|
@ -63,6 +63,8 @@ void ProtoConverter::visitType(
|
||||
std::string varName, paramName;
|
||||
createDeclAndParamList(_type, _dataType, varName, paramName);
|
||||
addCheckedVarDef(_dataType, varName, paramName, _value);
|
||||
// Update right padding of type
|
||||
m_isLastParamRightPadded = isDataTypeBytesOrString(_dataType);
|
||||
}
|
||||
|
||||
void ProtoConverter::appendVarDeclToOutput(
|
||||
@ -204,14 +206,23 @@ std::string ProtoConverter::addressValueAsString(unsigned _counter)
|
||||
.render();
|
||||
}
|
||||
|
||||
std::string ProtoConverter::fixedByteValueAsString(unsigned _width, unsigned _counter)
|
||||
std::string ProtoConverter::croppedString(
|
||||
unsigned _numBytes,
|
||||
unsigned _counter,
|
||||
bool _isHexLiteral
|
||||
)
|
||||
{
|
||||
// _numBytes can not be zero or exceed 32 bytes
|
||||
solAssert(
|
||||
(_width >= 1 && _width <= 32),
|
||||
"Proto ABIv2 Fuzzer: Fixed byte width is not between 1--32"
|
||||
_numBytes > 0 && _numBytes <= 32,
|
||||
"Proto ABIv2 fuzzer: Too short or too long a cropped string"
|
||||
);
|
||||
// Masked value must contain twice the number of nibble "f"'s as _width
|
||||
unsigned numMaskNibbles = _width * 2;
|
||||
|
||||
// Number of masked nibbles is twice the number of bytes for a
|
||||
// hex literal of _numBytes bytes. For a string literal, each nibble
|
||||
// is treated as a character.
|
||||
unsigned numMaskNibbles = _isHexLiteral ? _numBytes * 2 : _numBytes;
|
||||
|
||||
// Start position of substring equals totalHexStringLength - numMaskNibbles
|
||||
// totalHexStringLength = 64 + 2 = 66
|
||||
// e.g., 0x12345678901234567890123456789012 is a total of 66 characters
|
||||
@ -220,16 +231,133 @@ std::string ProtoConverter::fixedByteValueAsString(unsigned _width, unsigned _co
|
||||
// <-----------total length --------->
|
||||
// Note: This assumes that maskUnsignedIntToHex() invokes toHex(..., HexPrefix::Add)
|
||||
unsigned startPos = 66 - numMaskNibbles;
|
||||
// Extracts the least significant numMaskNibbles from the result
|
||||
// of maskUnsignedIntToHex().
|
||||
return maskUnsignedIntToHex(
|
||||
_counter,
|
||||
numMaskNibbles
|
||||
).substr(startPos, numMaskNibbles);
|
||||
}
|
||||
|
||||
std::string ProtoConverter::hexValueAsString(
|
||||
unsigned _numBytes,
|
||||
unsigned _counter,
|
||||
bool _isHexLiteral,
|
||||
bool _decorate
|
||||
)
|
||||
{
|
||||
solAssert(_numBytes > 0 && _numBytes <= 32,
|
||||
"Proto ABIv2 fuzzer: Invalid hex length"
|
||||
);
|
||||
|
||||
// If _decorate is set, then we return a hex"" or a "" string.
|
||||
if (_numBytes == 0)
|
||||
return Whiskers(R"(<?decorate><?isHex>hex</isHex>""</decorate>)")
|
||||
("decorate", _decorate)
|
||||
("isHex", _isHexLiteral)
|
||||
.render();
|
||||
|
||||
// Extracts the least significant numMaskNibbles from the result of "maskUnsignedIntToHex",
|
||||
// and replaces "0x" with "hex\"...\"" string.
|
||||
// This is needed because solidity interprets a 20-byte 0x prefixed hex literal as an address
|
||||
// payable type.
|
||||
return Whiskers(R"(hex"<value>")")
|
||||
("value", maskUnsignedIntToHex(_counter, numMaskNibbles).substr(startPos, numMaskNibbles))
|
||||
return Whiskers(R"(<?decorate><?isHex>hex</isHex>"</decorate><value><?decorate>"</decorate>)")
|
||||
("decorate", _decorate)
|
||||
("isHex", _isHexLiteral)
|
||||
("value", croppedString(_numBytes, _counter, _isHexLiteral))
|
||||
.render();
|
||||
}
|
||||
|
||||
std::string ProtoConverter::variableLengthValueAsString(
|
||||
unsigned _numBytes,
|
||||
unsigned _counter,
|
||||
bool _isHexLiteral
|
||||
)
|
||||
{
|
||||
solAssert(_numBytes >= 0 && _numBytes <= s_maxDynArrayLength,
|
||||
"Proto ABIv2 fuzzer: Invalid hex length"
|
||||
);
|
||||
if (_numBytes == 0)
|
||||
return Whiskers(R"(<?isHex>hex</isHex>"")")
|
||||
("isHex", _isHexLiteral)
|
||||
.render();
|
||||
|
||||
unsigned numBytesRemaining = _numBytes;
|
||||
// Stores the literal
|
||||
string output{};
|
||||
// If requested value is shorter than or exactly 32 bytes,
|
||||
// the literal is the return value of hexValueAsString.
|
||||
if (numBytesRemaining <= 32)
|
||||
output = hexValueAsString(
|
||||
numBytesRemaining,
|
||||
_counter,
|
||||
_isHexLiteral,
|
||||
/*decorate=*/false
|
||||
);
|
||||
// If requested value is longer than 32 bytes, the literal
|
||||
// is obtained by duplicating the return value of hexValueAsString
|
||||
// until we reach a value of the requested size.
|
||||
else
|
||||
{
|
||||
// Create a 32-byte value to be duplicated and
|
||||
// update number of bytes to be appended.
|
||||
// Stores the cached literal that saves us
|
||||
// (expensive) calls to keccak256.
|
||||
string cachedString = hexValueAsString(
|
||||
/*numBytes=*/32,
|
||||
_counter,
|
||||
_isHexLiteral,
|
||||
/*decorate=*/false
|
||||
);
|
||||
output = cachedString;
|
||||
numBytesRemaining -= 32;
|
||||
|
||||
// Append bytes from cachedString until
|
||||
// we create a value of desired length.
|
||||
unsigned numAppendedBytes;
|
||||
while (numBytesRemaining > 0)
|
||||
{
|
||||
// We append at most 32 bytes at a time
|
||||
numAppendedBytes = numBytesRemaining >= 32 ? 32 : numBytesRemaining;
|
||||
output += cachedString.substr(
|
||||
0,
|
||||
// Double the substring length for hex literals since each
|
||||
// character is actually half a byte (or a nibble).
|
||||
_isHexLiteral ? numAppendedBytes * 2 : numAppendedBytes
|
||||
);
|
||||
numBytesRemaining -= numAppendedBytes;
|
||||
}
|
||||
solAssert(
|
||||
numBytesRemaining == 0,
|
||||
"Proto ABIv2 fuzzer: Logic flaw in variable literal creation"
|
||||
);
|
||||
}
|
||||
|
||||
if (_isHexLiteral)
|
||||
solAssert(
|
||||
output.size() == 2 * _numBytes,
|
||||
"Proto ABIv2 fuzzer: Generated hex literal is of incorrect length"
|
||||
);
|
||||
else
|
||||
solAssert(
|
||||
output.size() == _numBytes,
|
||||
"Proto ABIv2 fuzzer: Generated string literal is of incorrect length"
|
||||
);
|
||||
|
||||
// Decorate output
|
||||
return Whiskers(R"(<?isHexLiteral>hex</isHexLiteral>"<value>")")
|
||||
("isHexLiteral", _isHexLiteral)
|
||||
("value", output)
|
||||
.render();
|
||||
}
|
||||
|
||||
std::string ProtoConverter::fixedByteValueAsString(unsigned _width, unsigned _counter)
|
||||
{
|
||||
solAssert(
|
||||
(_width >= 1 && _width <= 32),
|
||||
"Proto ABIv2 Fuzzer: Fixed byte width is not between 1--32"
|
||||
);
|
||||
return hexValueAsString(_width, _counter, /*isHexLiteral=*/true);
|
||||
}
|
||||
|
||||
std::string ProtoConverter::integerValueAsString(bool _sign, unsigned _width, unsigned _counter)
|
||||
{
|
||||
if (_sign)
|
||||
@ -314,10 +442,14 @@ void ProtoConverter::visit(ValueType const& _x)
|
||||
|
||||
void ProtoConverter::visit(DynamicByteArrayType const& _x)
|
||||
{
|
||||
bool isBytes = _x.type() == DynamicByteArrayType::BYTES;
|
||||
visitType(
|
||||
(_x.type() == DynamicByteArrayType::BYTES) ? DataType::BYTES : DataType::STRING,
|
||||
isBytes ? DataType::BYTES : DataType::STRING,
|
||||
bytesArrayTypeAsString(_x),
|
||||
bytesArrayValueAsString(getNextCounter())
|
||||
bytesArrayValueAsString(
|
||||
getNextCounter(),
|
||||
isBytes
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@ -367,7 +499,10 @@ std::string ProtoConverter::getValueByBaseType(ArrayType const& _x)
|
||||
case ArrayType::kBoolty:
|
||||
return boolValueAsString(getNextCounter());
|
||||
case ArrayType::kDynbytesty:
|
||||
return bytesArrayValueAsString(getNextCounter());
|
||||
return bytesArrayValueAsString(
|
||||
getNextCounter(),
|
||||
_x.dynbytesty().type() == DynamicByteArrayType::BYTES
|
||||
);
|
||||
// TODO: Implement structs.
|
||||
case ArrayType::kStty:
|
||||
case ArrayType::BASE_TYPE_ONEOF_NOT_SET:
|
||||
@ -523,18 +658,23 @@ void ProtoConverter::visit(ArrayType const& _x)
|
||||
{
|
||||
case ArrayType::kInty:
|
||||
baseType = getIntTypeAsString(_x.inty());
|
||||
m_isLastParamRightPadded = false;
|
||||
break;
|
||||
case ArrayType::kByty:
|
||||
baseType = getFixedByteTypeAsString(_x.byty());
|
||||
m_isLastParamRightPadded = false;
|
||||
break;
|
||||
case ArrayType::kAdty:
|
||||
baseType = getAddressTypeAsString(_x.adty());
|
||||
m_isLastParamRightPadded = false;
|
||||
break;
|
||||
case ArrayType::kBoolty:
|
||||
baseType = getBoolTypeAsString();
|
||||
m_isLastParamRightPadded = false;
|
||||
break;
|
||||
case ArrayType::kDynbytesty:
|
||||
baseType = bytesArrayTypeAsString(_x.dynbytesty());
|
||||
m_isLastParamRightPadded = true;
|
||||
break;
|
||||
case ArrayType::kStty:
|
||||
case ArrayType::BASE_TYPE_ONEOF_NOT_SET:
|
||||
@ -687,28 +827,42 @@ void ProtoConverter::visit(TestFunction const& _x)
|
||||
visit(_x.local_vars());
|
||||
|
||||
m_output << Whiskers(R"(
|
||||
uint returnVal = this.coder_public(<parameter_names>);
|
||||
uint returnVal = this.coder_public(<parameterNames>);
|
||||
if (returnVal != 0)
|
||||
return returnVal;
|
||||
|
||||
returnVal = this.coder_external(<parameter_names>);
|
||||
returnVal = this.coder_external(<parameterNames>);
|
||||
if (returnVal != 0)
|
||||
return uint(200000) + returnVal;
|
||||
|
||||
bytes memory argumentEncoding = abi.encode(<parameter_names>);
|
||||
<?atLeastOneVar>
|
||||
bytes memory argumentEncoding = abi.encode(<parameterNames>);
|
||||
|
||||
returnVal = checkEncodedCall(this.coder_public.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||
returnVal = checkEncodedCall(
|
||||
this.coder_public.selector,
|
||||
argumentEncoding,
|
||||
<invalidLengthFuzz>,
|
||||
<isRightPadded>
|
||||
);
|
||||
if (returnVal != 0)
|
||||
return returnVal;
|
||||
|
||||
returnVal = checkEncodedCall(this.coder_external.selector, argumentEncoding, <invalidLengthFuzz>);
|
||||
returnVal = checkEncodedCall(
|
||||
this.coder_external.selector,
|
||||
argumentEncoding,
|
||||
<invalidLengthFuzz>,
|
||||
<isRightPadded>
|
||||
);
|
||||
if (returnVal != 0)
|
||||
return uint(200000) + returnVal;
|
||||
</atLeastOneVar>
|
||||
return 0;
|
||||
}
|
||||
)")
|
||||
("parameter_names", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter))
|
||||
("parameterNames", dev::suffixedVariableNameList(s_varNamePrefix, 0, m_varCounter))
|
||||
("invalidLengthFuzz", std::to_string(_x.invalid_encoding_length()))
|
||||
("isRightPadded", isLastParamRightPadded() ? "true" : "false")
|
||||
("atLeastOneVar", m_varCounter > 0)
|
||||
.render();
|
||||
}
|
||||
|
||||
@ -724,14 +878,31 @@ void ProtoConverter::writeHelperFunctions()
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Accepts function selector, correct argument encoding, and length of invalid encoding and returns
|
||||
/// the correct and incorrect abi encoding for calling the function specified by the function selector.
|
||||
function createEncoding(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz)
|
||||
internal pure returns (bytes memory, bytes memory)
|
||||
/// Accepts function selector, correct argument encoding, and length of
|
||||
/// invalid encoding and returns the correct and incorrect abi encoding
|
||||
/// for calling the function specified by the function selector.
|
||||
function createEncoding(
|
||||
bytes4 funcSelector,
|
||||
bytes memory argumentEncoding,
|
||||
uint invalidLengthFuzz,
|
||||
bool isRightPadded
|
||||
) internal pure returns (bytes memory, bytes memory)
|
||||
{
|
||||
bytes memory validEncoding = new bytes(4 + argumentEncoding.length);
|
||||
// Ensure that invalidEncoding crops at least one and at most all bytes from correct encoding.
|
||||
uint invalidLength = invalidLengthFuzz % argumentEncoding.length;
|
||||
// Ensure that invalidEncoding crops at least 32 bytes (padding length
|
||||
// is at most 31 bytes) if `isRightPadded` is true.
|
||||
// This is because shorter bytes/string values (whose encoding is right
|
||||
// padded) can lead to successful decoding when fewer than 32 bytes have
|
||||
// been cropped in the worst case. In other words, if `isRightPadded` is
|
||||
// true, then
|
||||
// 0 <= invalidLength <= argumentEncoding.length - 32
|
||||
// otherwise
|
||||
// 0 <= invalidLength <= argumentEncoding.length - 1
|
||||
uint invalidLength;
|
||||
if (isRightPadded)
|
||||
invalidLength = invalidLengthFuzz % (argumentEncoding.length - 31);
|
||||
else
|
||||
invalidLength = invalidLengthFuzz % argumentEncoding.length;
|
||||
bytes memory invalidEncoding = new bytes(4 + invalidLength);
|
||||
for (uint i = 0; i < 4; i++)
|
||||
validEncoding[i] = invalidEncoding[i] = funcSelector[i];
|
||||
@ -742,12 +913,23 @@ void ProtoConverter::writeHelperFunctions()
|
||||
return (validEncoding, invalidEncoding);
|
||||
}
|
||||
|
||||
/// Accepts function selector, correct argument encoding, and an invalid encoding length as input.
|
||||
/// Returns a non-zero value if either call with correct encoding fails or call with incorrect encoding
|
||||
/// succeeds. Returns zero if both calls meet expectation.
|
||||
function checkEncodedCall(bytes4 funcSelector, bytes memory argumentEncoding, uint invalidLengthFuzz) public returns (uint)
|
||||
/// Accepts function selector, correct argument encoding, and an invalid
|
||||
/// encoding length as input. Returns a non-zero value if either call with
|
||||
/// correct encoding fails or call with incorrect encoding succeeds.
|
||||
/// Returns zero if both calls meet expectation.
|
||||
function checkEncodedCall(
|
||||
bytes4 funcSelector,
|
||||
bytes memory argumentEncoding,
|
||||
uint invalidLengthFuzz,
|
||||
bool isRightPadded
|
||||
) public returns (uint)
|
||||
{
|
||||
(bytes memory validEncoding, bytes memory invalidEncoding) = createEncoding(funcSelector, argumentEncoding, invalidLengthFuzz);
|
||||
(bytes memory validEncoding, bytes memory invalidEncoding) = createEncoding(
|
||||
funcSelector,
|
||||
argumentEncoding,
|
||||
invalidLengthFuzz,
|
||||
isRightPadded
|
||||
);
|
||||
(bool success, bytes memory returnVal) = address(this).call(validEncoding);
|
||||
uint returnCode = abi.decode(returnVal, (uint));
|
||||
// Return non-zero value if call fails for correct encoding
|
||||
|
@ -102,7 +102,8 @@ public:
|
||||
m_isStateVar(true),
|
||||
m_counter(0),
|
||||
m_varCounter(0),
|
||||
m_returnValue(1)
|
||||
m_returnValue(1),
|
||||
m_isLastParamRightPadded(false)
|
||||
{}
|
||||
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
@ -268,18 +269,16 @@ private:
|
||||
);
|
||||
}
|
||||
|
||||
// String and bytes literals are derived by hashing a monotonically increasing
|
||||
// counter and enclosing the said hash inside double quotes.
|
||||
std::string bytesArrayValueAsString(unsigned _counter)
|
||||
{
|
||||
return "\"" + toHex(hashUnsignedInt(_counter), HexPrefix::DontAdd) + "\"";
|
||||
}
|
||||
|
||||
std::string getQualifier(DataType _dataType)
|
||||
{
|
||||
return ((isValueType(_dataType) || m_isStateVar) ? "" : "memory");
|
||||
}
|
||||
|
||||
bool isLastParamRightPadded()
|
||||
{
|
||||
return m_isLastParamRightPadded;
|
||||
}
|
||||
|
||||
// Static declarations
|
||||
static std::string structTypeAsString(StructType const& _x);
|
||||
static std::string boolValueAsString(unsigned _counter);
|
||||
@ -288,6 +287,34 @@ private:
|
||||
static std::string integerValueAsString(bool _sign, unsigned _width, unsigned _counter);
|
||||
static std::string addressValueAsString(unsigned _counter);
|
||||
static std::string fixedByteValueAsString(unsigned _width, unsigned _counter);
|
||||
|
||||
/// Returns a hex literal if _isHexLiteral is true, a string literal otherwise.
|
||||
/// The size of the returned literal is _numBytes bytes.
|
||||
/// @param _decorate If true, the returned string is enclosed within double quotes
|
||||
/// if _isHexLiteral is false.
|
||||
/// @param _isHexLiteral If true, the returned string is enclosed within
|
||||
/// double quotes prefixed by the string "hex" if _decorate is true. If
|
||||
/// _decorate is false, the returned string is returned as-is.
|
||||
/// @return hex value as string
|
||||
static std::string hexValueAsString(
|
||||
unsigned _numBytes,
|
||||
unsigned _counter,
|
||||
bool _isHexLiteral,
|
||||
bool _decorate = true
|
||||
);
|
||||
|
||||
/// Concatenates the hash value obtained from monotonically increasing counter
|
||||
/// until the desired number of bytes determined by _numBytes.
|
||||
/// @param _width Desired number of bytes for hex value
|
||||
/// @param _counter A counter value used for creating a keccak256 hash
|
||||
/// @param _isHexLiteral Since this routine may be used to construct
|
||||
/// string or hex literals, this flag is used to construct a valid output.
|
||||
/// @return Valid hex or string literal of size _width bytes
|
||||
static std::string variableLengthValueAsString(
|
||||
unsigned _width,
|
||||
unsigned _counter,
|
||||
bool _isHexLiteral
|
||||
);
|
||||
static std::vector<std::pair<bool, unsigned>> arrayDimensionsAsPairVector(ArrayType const& _x);
|
||||
static std::string arrayDimInfoAsString(ArrayDimensionInfo const& _x);
|
||||
static void arrayDimensionsAsStringVector(
|
||||
@ -297,6 +324,7 @@ private:
|
||||
static std::string bytesArrayTypeAsString(DynamicByteArrayType const& _x);
|
||||
static std::string arrayTypeAsString(std::string const&, ArrayType const&);
|
||||
static std::string delimiterToString(Delimiter _delimiter);
|
||||
static std::string croppedString(unsigned _numBytes, unsigned _counter, bool _isHexLiteral);
|
||||
|
||||
// Static function definitions
|
||||
static bool isValueType(DataType _dataType)
|
||||
@ -347,6 +375,12 @@ private:
|
||||
return DataType::BYTES;
|
||||
}
|
||||
|
||||
/// Returns true if input is either a string or bytes, false otherwise.
|
||||
static bool isDataTypeBytesOrString(DataType _type)
|
||||
{
|
||||
return _type == DataType::STRING || _type == DataType::BYTES;
|
||||
}
|
||||
|
||||
// Convert _counter to string and return its keccak256 hash
|
||||
static u256 hashUnsignedInt(unsigned _counter)
|
||||
{
|
||||
@ -389,6 +423,33 @@ private:
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns a pseudo-random value for the size of a string/hex
|
||||
/// literal. Used for creating variable length hex/string literals.
|
||||
/// @param _counter Monotonically increasing counter value
|
||||
static unsigned getVarLength(unsigned _counter)
|
||||
{
|
||||
// Since _counter values are usually small, we use
|
||||
// this linear equation to make the number derived from
|
||||
// _counter approach a uniform distribution over
|
||||
// [0, s_maxDynArrayLength]
|
||||
return (_counter + 879) * 32 % (s_maxDynArrayLength + 1);
|
||||
}
|
||||
|
||||
/// Returns a hex/string literal of variable length whose value and
|
||||
/// size are pseudo-randomly determined from the counter value.
|
||||
/// @param _counter A monotonically increasing counter value
|
||||
/// @param _isHexLiteral Flag that indicates whether hex (if true) or
|
||||
/// string literal (false) is desired
|
||||
/// @return A variable length hex/string value
|
||||
static std::string bytesArrayValueAsString(unsigned _counter, bool _isHexLiteral)
|
||||
{
|
||||
return variableLengthValueAsString(
|
||||
getVarLength(_counter),
|
||||
_counter,
|
||||
_isHexLiteral
|
||||
);
|
||||
}
|
||||
|
||||
/// Contains the test program
|
||||
std::ostringstream m_output;
|
||||
/// Temporary storage for state variable definitions
|
||||
@ -405,8 +466,13 @@ private:
|
||||
unsigned m_varCounter;
|
||||
/// Monotonically increasing return value for error reporting
|
||||
unsigned m_returnValue;
|
||||
/// Flag that indicates if last parameter passed to a function call
|
||||
/// is of a type that is going to be right padded by the ABI
|
||||
/// encoder.
|
||||
bool m_isLastParamRightPadded;
|
||||
static unsigned constexpr s_maxArrayLength = 4;
|
||||
static unsigned constexpr s_maxArrayDimensions = 4;
|
||||
static unsigned constexpr s_maxDynArrayLength = 256;
|
||||
/// Prefixes for declared and parameterized variable names
|
||||
static auto constexpr s_varNamePrefix = "x_";
|
||||
static auto constexpr s_paramNamePrefix = "c_";
|
||||
|
@ -16,15 +16,29 @@
|
||||
*/
|
||||
|
||||
#include <test/tools/ossfuzz/protoToYul.h>
|
||||
#include <libdevcore/StringUtils.h>
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
#include <test/tools/ossfuzz/yulOptimizerFuzzDictionary.h>
|
||||
|
||||
#include <libyul/Exceptions.h>
|
||||
|
||||
#include <libdevcore/StringUtils.h>
|
||||
|
||||
#include <boost/range/algorithm_ext/erase.hpp>
|
||||
#include <boost/algorithm/cxx11/all_of.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace yul::test::yul_fuzzer;
|
||||
using namespace dev;
|
||||
|
||||
string ProtoConverter::createHex(string const& _hexBytes) const
|
||||
string ProtoConverter::dictionaryToken(HexPrefix _p)
|
||||
{
|
||||
unsigned indexVar = m_inputSize * m_inputSize + counter();
|
||||
std::string token = hexDictionary[indexVar % hexDictionary.size()];
|
||||
yulAssert(token.size() <= 64, "Proto Fuzzer: Dictionary token too large");
|
||||
|
||||
return _p == HexPrefix::Add ? "0x" + token : token;
|
||||
}
|
||||
|
||||
string ProtoConverter::createHex(string const& _hexBytes)
|
||||
{
|
||||
string tmp{_hexBytes};
|
||||
if (!tmp.empty())
|
||||
@ -35,12 +49,14 @@ string ProtoConverter::createHex(string const& _hexBytes) const
|
||||
tmp = tmp.substr(0, 64);
|
||||
}
|
||||
// We need this awkward if case because hex literals cannot be empty.
|
||||
// Use a dictionary token.
|
||||
if (tmp.empty())
|
||||
tmp = "1";
|
||||
tmp = dictionaryToken(HexPrefix::DontAdd);
|
||||
yulAssert(tmp.size() <= 64, "Proto Fuzzer: Dictionary token too large");
|
||||
return tmp;
|
||||
}
|
||||
|
||||
string ProtoConverter::createAlphaNum(string const& _strBytes) const
|
||||
string ProtoConverter::createAlphaNum(string const& _strBytes)
|
||||
{
|
||||
string tmp{_strBytes};
|
||||
if (!tmp.empty())
|
||||
@ -53,51 +69,18 @@ string ProtoConverter::createAlphaNum(string const& _strBytes) const
|
||||
return tmp;
|
||||
}
|
||||
|
||||
bool ProtoConverter::isCaseLiteralUnique(Literal const& _x)
|
||||
{
|
||||
dev::u256 mpCaseLiteralValue;
|
||||
bool isUnique = false;
|
||||
|
||||
switch (_x.literal_oneof_case())
|
||||
{
|
||||
case Literal::kIntval:
|
||||
mpCaseLiteralValue = dev::u256(_x.intval());
|
||||
break;
|
||||
case Literal::kHexval:
|
||||
// We need to ask boost mp library to treat this
|
||||
// as a hex value. Hence the "0x" prefix.
|
||||
mpCaseLiteralValue = dev::u256("0x" + createHex(_x.hexval()));
|
||||
break;
|
||||
case Literal::kStrval:
|
||||
mpCaseLiteralValue = dev::u256(dev::h256(createAlphaNum(_x.strval()), dev::h256::FromBinary, dev::h256::AlignLeft));
|
||||
break;
|
||||
case Literal::LITERAL_ONEOF_NOT_SET:
|
||||
// If the proto generator does not generate a valid Literal
|
||||
// we generate a case 1:
|
||||
mpCaseLiteralValue = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
isUnique = m_switchLiteralSetPerScope.top().insert(mpCaseLiteralValue).second;
|
||||
return isUnique;
|
||||
}
|
||||
|
||||
void ProtoConverter::visit(Literal const& _x)
|
||||
string ProtoConverter::visit(Literal const& _x)
|
||||
{
|
||||
switch (_x.literal_oneof_case())
|
||||
{
|
||||
case Literal::kIntval:
|
||||
m_output << _x.intval();
|
||||
break;
|
||||
return to_string(_x.intval());
|
||||
case Literal::kHexval:
|
||||
m_output << "0x" << createHex(_x.hexval());
|
||||
break;
|
||||
return "0x" + createHex(_x.hexval());
|
||||
case Literal::kStrval:
|
||||
m_output << "\"" << createAlphaNum(_x.strval()) << "\"";
|
||||
break;
|
||||
return "\"" + createAlphaNum(_x.strval()) + "\"";
|
||||
case Literal::LITERAL_ONEOF_NOT_SET:
|
||||
m_output << "1";
|
||||
break;
|
||||
return dictionaryToken();
|
||||
}
|
||||
}
|
||||
|
||||
@ -116,7 +99,7 @@ void ProtoConverter::visit(Expression const& _x)
|
||||
visit(_x.varref());
|
||||
break;
|
||||
case Expression::kCons:
|
||||
visit(_x.cons());
|
||||
m_output << visit(_x.cons());
|
||||
break;
|
||||
case Expression::kBinop:
|
||||
visit(_x.binop());
|
||||
@ -134,7 +117,7 @@ void ProtoConverter::visit(Expression const& _x)
|
||||
visit(_x.func_expr());
|
||||
break;
|
||||
case Expression::EXPR_ONEOF_NOT_SET:
|
||||
m_output << "1";
|
||||
m_output << dictionaryToken();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -693,12 +676,64 @@ void ProtoConverter::visit(BoundedForStmt const& _x)
|
||||
|
||||
void ProtoConverter::visit(CaseStmt const& _x)
|
||||
{
|
||||
// Silently ignore duplicate case literals
|
||||
if (isCaseLiteralUnique(_x.case_lit()))
|
||||
string literal = visit(_x.case_lit());
|
||||
// u256 value of literal
|
||||
u256 literalVal;
|
||||
|
||||
// Convert string to u256 before looking for duplicate case literals
|
||||
if (_x.case_lit().has_strval())
|
||||
{
|
||||
m_output << "case ";
|
||||
visit(_x.case_lit());
|
||||
m_output << " ";
|
||||
// Since string literals returned by the Literal visitor are enclosed within
|
||||
// double quotes (like this "\"<string>\""), their size is at least two in the worst case
|
||||
// that <string> is empty. Here we assert this invariant.
|
||||
yulAssert(literal.size() >= 2, "Proto fuzzer: String literal too short");
|
||||
// This variable stores the <string> part i.e., literal minus the first and last
|
||||
// double quote characters. This is used to compute the keccak256 hash of the
|
||||
// string literal. The hashing is done to check whether we are about to create
|
||||
// a case statement containing a case literal that has already been used in a
|
||||
// previous case statement. If the hash (u256 value) matches a previous hash,
|
||||
// then we simply don't create a new case statement.
|
||||
string noDoubleQuoteStr = "";
|
||||
if (literal.size() > 2)
|
||||
{
|
||||
// Ensure that all characters in the string literal except the first
|
||||
// and the last (double quote characters) are alphanumeric.
|
||||
yulAssert(
|
||||
boost::algorithm::all_of(literal.begin() + 1, literal.end() - 2, [=](char c) -> bool {
|
||||
return std::isalpha(c) || std::isdigit(c);
|
||||
}),
|
||||
"Proto fuzzer: Invalid string literal encountered"
|
||||
);
|
||||
|
||||
// Make a copy because literal will need to be used later
|
||||
noDoubleQuoteStr = literal.substr(1, literal.size() - 2);
|
||||
}
|
||||
// Hash the result to check for duplicate case literal strings
|
||||
literalVal = u256(h256(noDoubleQuoteStr, h256::FromBinary, h256::AlignLeft));
|
||||
|
||||
// Make sure that an empty string literal evaluates to zero. This is to detect creation of
|
||||
// duplicate case literals like so
|
||||
// switch (x)
|
||||
// {
|
||||
// case "": { x := 0 }
|
||||
// case 0: { x:= 1 } // Case statement with duplicate literal is invalid
|
||||
// } // This snippet will not be parsed successfully.
|
||||
if (noDoubleQuoteStr.empty())
|
||||
yulAssert(literalVal == 0, "Proto fuzzer: Empty string does not evaluate to zero");
|
||||
}
|
||||
else
|
||||
literalVal = u256(literal);
|
||||
|
||||
// Check if set insertion fails (case literal present) or succeeds (case literal
|
||||
// absent).
|
||||
bool isUnique = m_switchLiteralSetPerScope.top().insert(literalVal).second;
|
||||
|
||||
// It is fine to bail out if we encounter a duplicate case literal because
|
||||
// we can be assured that the switch statement is well-formed i.e., contains
|
||||
// at least one case statement or a default block.
|
||||
if (isUnique)
|
||||
{
|
||||
m_output << "case " << literal << " ";
|
||||
visit(_x.case_block());
|
||||
}
|
||||
}
|
||||
@ -965,6 +1000,9 @@ void ProtoConverter::visit(FunctionDefinition const& _x)
|
||||
|
||||
void ProtoConverter::visit(Program const& _x)
|
||||
{
|
||||
// Initialize input size
|
||||
m_inputSize = _x.ByteSizeLong();
|
||||
|
||||
/* Program template is as follows
|
||||
* Four Globals a_0, a_1, a_2, and a_3 to hold up to four function return values
|
||||
*
|
||||
|
@ -46,6 +46,8 @@ public:
|
||||
m_inForBodyScope = false;
|
||||
m_inForInitScope = false;
|
||||
m_numNestedForLoops = 0;
|
||||
m_counter = 0;
|
||||
m_inputSize = 0;
|
||||
}
|
||||
ProtoConverter(ProtoConverter const&) = delete;
|
||||
ProtoConverter(ProtoConverter&&) = delete;
|
||||
@ -55,7 +57,7 @@ private:
|
||||
void visit(BinaryOp const&);
|
||||
void visit(Block const&);
|
||||
void visit(SpecialBlock const&);
|
||||
void visit(Literal const&);
|
||||
std::string visit(Literal const&);
|
||||
void visit(VarRef const&);
|
||||
void visit(Expression const&);
|
||||
void visit(VarDecl const&);
|
||||
@ -89,13 +91,13 @@ private:
|
||||
void visit(FunctionDefinitionSingleReturnVal const&);
|
||||
void visit(FunctionDefinitionMultiReturnVal const&);
|
||||
void visit(Program const&);
|
||||
template <class T>
|
||||
void visit(google::protobuf::RepeatedPtrField<T> const& _repeated_field);
|
||||
void registerFunction(FunctionDefinition const&);
|
||||
|
||||
std::string createHex(std::string const& _hexBytes) const;
|
||||
std::string createAlphaNum(std::string const& _strBytes) const;
|
||||
bool isCaseLiteralUnique(Literal const&);
|
||||
std::string createHex(std::string const& _hexBytes);
|
||||
|
||||
/// Accepts an arbitrary string, removes all characters that are neither
|
||||
/// alphabets nor digits from it and returns the said string.
|
||||
std::string createAlphaNum(std::string const& _strBytes);
|
||||
enum class NumFunctionReturns
|
||||
{
|
||||
None,
|
||||
@ -127,6 +129,20 @@ private:
|
||||
break;
|
||||
}
|
||||
}
|
||||
/// Returns a pseudo-random dictionary token.
|
||||
/// @param _p Enum that decides if the returned token is hex prefixed ("0x") or not
|
||||
/// @return Dictionary token at the index computed using a
|
||||
/// monotonically increasing counter as follows:
|
||||
/// index = (m_inputSize * m_inputSize + counter) % dictionarySize
|
||||
/// where m_inputSize is the size of the protobuf input and
|
||||
/// dictionarySize is the total number of entries in the dictionary.
|
||||
std::string dictionaryToken(dev::HexPrefix _p = dev::HexPrefix::Add);
|
||||
|
||||
/// Returns a monotonically increasing counter that starts from zero.
|
||||
unsigned counter()
|
||||
{
|
||||
return m_counter++;
|
||||
}
|
||||
|
||||
std::ostringstream m_output;
|
||||
// Number of live variables in inner scope of a function
|
||||
@ -151,6 +167,10 @@ private:
|
||||
unsigned m_numNestedForLoops;
|
||||
// predicate to keep track of for loop init scope
|
||||
bool m_inForInitScope;
|
||||
/// Monotonically increasing counter
|
||||
unsigned m_counter;
|
||||
/// Size of protobuf input
|
||||
unsigned m_inputSize;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -25,14 +25,12 @@ void yulFuzzerUtil::interpret(
|
||||
shared_ptr<yul::Block> _ast,
|
||||
Dialect const& _dialect,
|
||||
size_t _maxSteps,
|
||||
size_t _maxTraceSize,
|
||||
size_t _maxMemory
|
||||
size_t _maxTraceSize
|
||||
)
|
||||
{
|
||||
InterpreterState state;
|
||||
state.maxTraceSize = _maxTraceSize;
|
||||
state.maxSteps = _maxSteps;
|
||||
state.maxMemSize = _maxMemory;
|
||||
Interpreter interpreter(state, _dialect);
|
||||
interpreter(*_ast);
|
||||
state.dumpTraceAndState(_os);
|
||||
|
@ -30,12 +30,10 @@ struct yulFuzzerUtil
|
||||
std::shared_ptr<yul::Block> _ast,
|
||||
Dialect const& _dialect,
|
||||
size_t _maxSteps = maxSteps,
|
||||
size_t _maxTraceSize = maxTraceSize,
|
||||
size_t _maxMemory = maxMemory
|
||||
size_t _maxTraceSize = maxTraceSize
|
||||
);
|
||||
static size_t constexpr maxSteps = 100;
|
||||
static size_t constexpr maxTraceSize = 75;
|
||||
static size_t constexpr maxMemory = 0x200;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
777
test/tools/ossfuzz/yulOptimizerFuzzDictionary.h
Normal file
777
test/tools/ossfuzz/yulOptimizerFuzzDictionary.h
Normal file
@ -0,0 +1,777 @@
|
||||
|
||||
static const std::vector<std::string> hexDictionary = {
|
||||
"0",
|
||||
"1",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1f",
|
||||
"9f",
|
||||
"a0",
|
||||
"a1",
|
||||
"ff",
|
||||
"100",
|
||||
"101",
|
||||
"10",
|
||||
"100",
|
||||
"1000",
|
||||
"10000",
|
||||
"100000",
|
||||
"1000000",
|
||||
"10000000",
|
||||
"100000000",
|
||||
"1000000000",
|
||||
"10000000000",
|
||||
"100000000000",
|
||||
"1000000000000",
|
||||
"10000000000000",
|
||||
"100000000000000",
|
||||
"1000000000000000",
|
||||
"10000000000000000",
|
||||
"100000000000000000",
|
||||
"1000000000000000000",
|
||||
"10000000000000000000",
|
||||
"100000000000000000000",
|
||||
"1000000000000000000000",
|
||||
"10000000000000000000000",
|
||||
"100000000000000000000000",
|
||||
"1000000000000000000000000",
|
||||
"10000000000000000000000000",
|
||||
"100000000000000000000000000",
|
||||
"1000000000000000000000000000",
|
||||
"10000000000000000000000000000",
|
||||
"100000000000000000000000000000",
|
||||
"1000000000000000000000000000000",
|
||||
"10000000000000000000000000000000",
|
||||
"100000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000000000000000",
|
||||
"10000000000000000000000000000000000000000000000000000000000000",
|
||||
"100000000000000000000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000000000000000000",
|
||||
"1000000000000000000000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000000001",
|
||||
"100000000000000000000000000000000001",
|
||||
"10000000000000000000000000000000001",
|
||||
"1000000000000000000000000000000001",
|
||||
"100000000000000000000000000000001",
|
||||
"10000000000000000000000000000001",
|
||||
"1000000000000000000000000000001",
|
||||
"100000000000000000000000000001",
|
||||
"10000000000000000000000000001",
|
||||
"1000000000000000000000000001",
|
||||
"100000000000000000000000001",
|
||||
"10000000000000000000000001",
|
||||
"1000000000000000000000001",
|
||||
"100000000000000000000001",
|
||||
"10000000000000000000001",
|
||||
"1000000000000000000001",
|
||||
"100000000000000000001",
|
||||
"10000000000000000001",
|
||||
"1000000000000000001",
|
||||
"100000000000000001",
|
||||
"10000000000000001",
|
||||
"1000000000000001",
|
||||
"100000000000001",
|
||||
"10000000000001",
|
||||
"1000000000001",
|
||||
"100000000001",
|
||||
"10000000001",
|
||||
"1000000001",
|
||||
"100000001",
|
||||
"10000001",
|
||||
"1000001",
|
||||
"100001",
|
||||
"10001",
|
||||
"1001",
|
||||
"101",
|
||||
"11",
|
||||
"1f",
|
||||
"1ff",
|
||||
"1fff",
|
||||
"1ffff",
|
||||
"1fffff",
|
||||
"1ffffff",
|
||||
"1fffffff",
|
||||
"1ffffffff",
|
||||
"1fffffffff",
|
||||
"1ffffffffff",
|
||||
"1fffffffffff",
|
||||
"1ffffffffffff",
|
||||
"1fffffffffffff",
|
||||
"1ffffffffffffff",
|
||||
"1fffffffffffffff",
|
||||
"1ffffffffffffffff",
|
||||
"1fffffffffffffffff",
|
||||
"1ffffffffffffffffff",
|
||||
"1fffffffffffffffffff",
|
||||
"1ffffffffffffffffffff",
|
||||
"1fffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"1fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"2",
|
||||
"20",
|
||||
"200",
|
||||
"2000",
|
||||
"20000",
|
||||
"200000",
|
||||
"2000000",
|
||||
"20000000",
|
||||
"200000000",
|
||||
"2000000000",
|
||||
"20000000000",
|
||||
"200000000000",
|
||||
"2000000000000",
|
||||
"20000000000000",
|
||||
"200000000000000",
|
||||
"2000000000000000",
|
||||
"20000000000000000",
|
||||
"200000000000000000",
|
||||
"2000000000000000000",
|
||||
"20000000000000000000",
|
||||
"200000000000000000000",
|
||||
"2000000000000000000000",
|
||||
"20000000000000000000000",
|
||||
"200000000000000000000000",
|
||||
"2000000000000000000000000",
|
||||
"20000000000000000000000000",
|
||||
"200000000000000000000000000",
|
||||
"2000000000000000000000000000",
|
||||
"20000000000000000000000000000",
|
||||
"200000000000000000000000000000",
|
||||
"2000000000000000000000000000000",
|
||||
"20000000000000000000000000000000",
|
||||
"200000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000000000000000",
|
||||
"20000000000000000000000000000000000000000000000000000000000000",
|
||||
"200000000000000000000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000000000000000000",
|
||||
"2000000000000000000000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000000001",
|
||||
"200000000000000000000000000000000001",
|
||||
"20000000000000000000000000000000001",
|
||||
"2000000000000000000000000000000001",
|
||||
"200000000000000000000000000000001",
|
||||
"20000000000000000000000000000001",
|
||||
"2000000000000000000000000000001",
|
||||
"200000000000000000000000000001",
|
||||
"20000000000000000000000000001",
|
||||
"2000000000000000000000000001",
|
||||
"200000000000000000000000001",
|
||||
"20000000000000000000000001",
|
||||
"2000000000000000000000001",
|
||||
"200000000000000000000001",
|
||||
"20000000000000000000001",
|
||||
"2000000000000000000001",
|
||||
"200000000000000000001",
|
||||
"20000000000000000001",
|
||||
"2000000000000000001",
|
||||
"200000000000000001",
|
||||
"20000000000000001",
|
||||
"2000000000000001",
|
||||
"200000000000001",
|
||||
"20000000000001",
|
||||
"2000000000001",
|
||||
"200000000001",
|
||||
"20000000001",
|
||||
"2000000001",
|
||||
"200000001",
|
||||
"20000001",
|
||||
"2000001",
|
||||
"200001",
|
||||
"20001",
|
||||
"2001",
|
||||
"201",
|
||||
"21",
|
||||
"3",
|
||||
"3f",
|
||||
"3ff",
|
||||
"3fff",
|
||||
"3ffff",
|
||||
"3fffff",
|
||||
"3ffffff",
|
||||
"3fffffff",
|
||||
"3ffffffff",
|
||||
"3fffffffff",
|
||||
"3ffffffffff",
|
||||
"3fffffffffff",
|
||||
"3ffffffffffff",
|
||||
"3fffffffffffff",
|
||||
"3ffffffffffffff",
|
||||
"3fffffffffffffff",
|
||||
"3ffffffffffffffff",
|
||||
"3fffffffffffffffff",
|
||||
"3ffffffffffffffffff",
|
||||
"3fffffffffffffffffff",
|
||||
"3ffffffffffffffffffff",
|
||||
"3fffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"3fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"4",
|
||||
"40",
|
||||
"400",
|
||||
"4000",
|
||||
"40000",
|
||||
"400000",
|
||||
"4000000",
|
||||
"40000000",
|
||||
"400000000",
|
||||
"4000000000",
|
||||
"40000000000",
|
||||
"400000000000",
|
||||
"4000000000000",
|
||||
"40000000000000",
|
||||
"400000000000000",
|
||||
"4000000000000000",
|
||||
"40000000000000000",
|
||||
"400000000000000000",
|
||||
"4000000000000000000",
|
||||
"40000000000000000000",
|
||||
"400000000000000000000",
|
||||
"4000000000000000000000",
|
||||
"40000000000000000000000",
|
||||
"400000000000000000000000",
|
||||
"4000000000000000000000000",
|
||||
"40000000000000000000000000",
|
||||
"400000000000000000000000000",
|
||||
"4000000000000000000000000000",
|
||||
"40000000000000000000000000000",
|
||||
"400000000000000000000000000000",
|
||||
"4000000000000000000000000000000",
|
||||
"40000000000000000000000000000000",
|
||||
"400000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000000000000000",
|
||||
"40000000000000000000000000000000000000000000000000000000000000",
|
||||
"400000000000000000000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000000000000000000",
|
||||
"4000000000000000000000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000000001",
|
||||
"400000000000000000000000000000000001",
|
||||
"40000000000000000000000000000000001",
|
||||
"4000000000000000000000000000000001",
|
||||
"400000000000000000000000000000001",
|
||||
"40000000000000000000000000000001",
|
||||
"4000000000000000000000000000001",
|
||||
"400000000000000000000000000001",
|
||||
"40000000000000000000000000001",
|
||||
"4000000000000000000000000001",
|
||||
"400000000000000000000000001",
|
||||
"40000000000000000000000001",
|
||||
"4000000000000000000000001",
|
||||
"400000000000000000000001",
|
||||
"40000000000000000000001",
|
||||
"4000000000000000000001",
|
||||
"400000000000000000001",
|
||||
"40000000000000000001",
|
||||
"4000000000000000001",
|
||||
"400000000000000001",
|
||||
"40000000000000001",
|
||||
"4000000000000001",
|
||||
"400000000000001",
|
||||
"40000000000001",
|
||||
"4000000000001",
|
||||
"400000000001",
|
||||
"40000000001",
|
||||
"4000000001",
|
||||
"400000001",
|
||||
"40000001",
|
||||
"4000001",
|
||||
"400001",
|
||||
"40001",
|
||||
"4001",
|
||||
"401",
|
||||
"41",
|
||||
"5",
|
||||
"7",
|
||||
"7f",
|
||||
"7ff",
|
||||
"7fff",
|
||||
"7ffff",
|
||||
"7fffff",
|
||||
"7ffffff",
|
||||
"7fffffff",
|
||||
"7ffffffff",
|
||||
"7fffffffff",
|
||||
"7ffffffffff",
|
||||
"7fffffffffff",
|
||||
"7ffffffffffff",
|
||||
"7fffffffffffff",
|
||||
"7ffffffffffffff",
|
||||
"7fffffffffffffff",
|
||||
"7ffffffffffffffff",
|
||||
"7fffffffffffffffff",
|
||||
"7ffffffffffffffffff",
|
||||
"7fffffffffffffffffff",
|
||||
"7ffffffffffffffffffff",
|
||||
"7fffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"8",
|
||||
"80",
|
||||
"800",
|
||||
"8000",
|
||||
"80000",
|
||||
"800000",
|
||||
"8000000",
|
||||
"80000000",
|
||||
"800000000",
|
||||
"8000000000",
|
||||
"80000000000",
|
||||
"800000000000",
|
||||
"8000000000000",
|
||||
"80000000000000",
|
||||
"800000000000000",
|
||||
"8000000000000000",
|
||||
"80000000000000000",
|
||||
"800000000000000000",
|
||||
"8000000000000000000",
|
||||
"80000000000000000000",
|
||||
"800000000000000000000",
|
||||
"8000000000000000000000",
|
||||
"80000000000000000000000",
|
||||
"800000000000000000000000",
|
||||
"8000000000000000000000000",
|
||||
"80000000000000000000000000",
|
||||
"800000000000000000000000000",
|
||||
"8000000000000000000000000000",
|
||||
"80000000000000000000000000000",
|
||||
"800000000000000000000000000000",
|
||||
"8000000000000000000000000000000",
|
||||
"80000000000000000000000000000000",
|
||||
"800000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000000000000000",
|
||||
"80000000000000000000000000000000000000000000000000000000000000",
|
||||
"800000000000000000000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000000000000000000",
|
||||
"8000000000000000000000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000000001",
|
||||
"800000000000000000000000000000000001",
|
||||
"80000000000000000000000000000000001",
|
||||
"8000000000000000000000000000000001",
|
||||
"800000000000000000000000000000001",
|
||||
"80000000000000000000000000000001",
|
||||
"8000000000000000000000000000001",
|
||||
"800000000000000000000000000001",
|
||||
"80000000000000000000000000001",
|
||||
"8000000000000000000000000001",
|
||||
"800000000000000000000000001",
|
||||
"80000000000000000000000001",
|
||||
"8000000000000000000000001",
|
||||
"800000000000000000000001",
|
||||
"80000000000000000000001",
|
||||
"8000000000000000000001",
|
||||
"800000000000000000001",
|
||||
"80000000000000000001",
|
||||
"8000000000000000001",
|
||||
"800000000000000001",
|
||||
"80000000000000001",
|
||||
"8000000000000001",
|
||||
"800000000000001",
|
||||
"80000000000001",
|
||||
"8000000000001",
|
||||
"800000000001",
|
||||
"80000000001",
|
||||
"8000000001",
|
||||
"800000001",
|
||||
"80000001",
|
||||
"8000001",
|
||||
"800001",
|
||||
"80001",
|
||||
"8001",
|
||||
"801",
|
||||
"81",
|
||||
"9",
|
||||
"f",
|
||||
"ff",
|
||||
"fff",
|
||||
"ffff",
|
||||
"fffff",
|
||||
"ffffff",
|
||||
"fffffff",
|
||||
"ffffffff",
|
||||
"fffffffff",
|
||||
"ffffffffff",
|
||||
"fffffffffff",
|
||||
"ffffffffffff",
|
||||
"fffffffffffff",
|
||||
"ffffffffffffff",
|
||||
"fffffffffffffff",
|
||||
"ffffffffffffffff",
|
||||
"fffffffffffffffff",
|
||||
"ffffffffffffffffff",
|
||||
"fffffffffffffffffff",
|
||||
"ffffffffffffffffffff",
|
||||
"fffffffffffffffffffff",
|
||||
"ffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
|
||||
"ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
|
||||
};
|
@ -63,13 +63,11 @@ u256 readZeroExtended(bytes const& _data, u256 const& _offset)
|
||||
/// Copy @a _size bytes of @a _source at offset @a _sourceOffset to
|
||||
/// @a _target at offset @a _targetOffset. Behaves as if @a _source would
|
||||
/// continue with an infinite sequence of zero bytes beyond its end.
|
||||
/// Asserts the target is large enough to hold the copied segment.
|
||||
void copyZeroExtended(
|
||||
bytes& _target, bytes const& _source,
|
||||
map<u256, uint8_t>& _target, bytes const& _source,
|
||||
size_t _targetOffset, size_t _sourceOffset, size_t _size
|
||||
)
|
||||
{
|
||||
yulAssert(_targetOffset + _size <= _target.size(), "");
|
||||
for (size_t i = 0; i < _size; ++i)
|
||||
_target[_targetOffset + i] = _sourceOffset + i < _source.size() ? _source[_sourceOffset + i] : 0;
|
||||
}
|
||||
@ -176,7 +174,7 @@ u256 EVMInstructionInterpreter::eval(
|
||||
return u256("0x1234cafe1234cafe1234cafe") + arg[0];
|
||||
uint64_t offset = uint64_t(arg[0] & uint64_t(-1));
|
||||
uint64_t size = uint64_t(arg[1] & uint64_t(-1));
|
||||
return u256(keccak256(bytesConstRef(m_state.memory.data() + offset, size)));
|
||||
return u256(keccak256(readMemory(offset, size)));
|
||||
}
|
||||
case Instruction::ADDRESS:
|
||||
return m_state.address;
|
||||
@ -251,16 +249,16 @@ u256 EVMInstructionInterpreter::eval(
|
||||
// --------------- memory / storage / logs ---------------
|
||||
case Instruction::MLOAD:
|
||||
if (accessMemory(arg[0], 0x20))
|
||||
return u256(*reinterpret_cast<h256 const*>(m_state.memory.data() + size_t(arg[0])));
|
||||
return readMemoryWord(arg[0]);
|
||||
else
|
||||
return 0x1234 + arg[0];
|
||||
case Instruction::MSTORE:
|
||||
if (accessMemory(arg[0], 0x20))
|
||||
*reinterpret_cast<h256*>(m_state.memory.data() + size_t(arg[0])) = h256(arg[1]);
|
||||
writeMemoryWord(arg[0], arg[1]);
|
||||
return 0;
|
||||
case Instruction::MSTORE8:
|
||||
if (accessMemory(arg[0], 1))
|
||||
m_state.memory[size_t(arg[0])] = uint8_t(arg[1] & 0xff);
|
||||
m_state.memory[arg[0]] = uint8_t(arg[1] & 0xff);
|
||||
return 0;
|
||||
case Instruction::SLOAD:
|
||||
return m_state.storage[h256(arg[0])];
|
||||
@ -319,7 +317,7 @@ u256 EVMInstructionInterpreter::eval(
|
||||
{
|
||||
bytes data;
|
||||
if (accessMemory(arg[0], arg[1]))
|
||||
data = bytesConstRef(m_state.memory.data() + size_t(arg[0]), size_t(arg[1])).toBytes();
|
||||
data = readMemory(arg[0], arg[1]);
|
||||
logTrace(_instruction, arg, data);
|
||||
throw ExplicitlyTerminated();
|
||||
}
|
||||
@ -455,12 +453,7 @@ bool EVMInstructionInterpreter::accessMemory(u256 const& _offset, u256 const& _s
|
||||
{
|
||||
u256 newSize = (_offset + _size + 0x1f) & ~u256(0x1f);
|
||||
m_state.msize = max(m_state.msize, newSize);
|
||||
if (newSize < m_state.maxMemSize)
|
||||
{
|
||||
if (m_state.memory.size() < newSize)
|
||||
m_state.memory.resize(size_t(newSize));
|
||||
return true;
|
||||
}
|
||||
return _size <= 0xffff;
|
||||
}
|
||||
else
|
||||
m_state.msize = u256(-1);
|
||||
@ -468,6 +461,27 @@ bool EVMInstructionInterpreter::accessMemory(u256 const& _offset, u256 const& _s
|
||||
return false;
|
||||
}
|
||||
|
||||
bytes EVMInstructionInterpreter::readMemory(u256 const& _offset, u256 const& _size)
|
||||
{
|
||||
yulAssert(_size <= 0xffff, "Too large read.");
|
||||
bytes data(size_t(_size), uint8_t(0));
|
||||
for (size_t i = 0; i < data.size(); ++i)
|
||||
data[i] = m_state.memory[_offset + i];
|
||||
return data;
|
||||
}
|
||||
|
||||
u256 EVMInstructionInterpreter::readMemoryWord(u256 const& _offset)
|
||||
{
|
||||
return u256(h256(readMemory(_offset, 32)));
|
||||
}
|
||||
|
||||
void EVMInstructionInterpreter::writeMemoryWord(u256 const& _offset, u256 const& _value)
|
||||
{
|
||||
for (size_t i = 0; i < 32; i++)
|
||||
m_state.memory[_offset + i] = uint8_t((_value >> (8 * (31 - i))) & 0xff);
|
||||
}
|
||||
|
||||
|
||||
void EVMInstructionInterpreter::logTrace(dev::eth::Instruction _instruction, std::vector<u256> const& _arguments, bytes const& _data)
|
||||
{
|
||||
logTrace(dev::eth::instructionInfo(_instruction).name, _arguments, _data);
|
||||
|
@ -75,9 +75,19 @@ public:
|
||||
dev::u256 evalBuiltin(BuiltinFunctionForEVM const& _fun, std::vector<dev::u256> const& _arguments);
|
||||
|
||||
private:
|
||||
/// Resizes the memory to accommodate the memory access.
|
||||
/// @returns false if memory would have to be expanded beyond m_state.maxMemSize.
|
||||
/// Checks if the memory access is not too large for the interpreter and adjusts
|
||||
/// msize accordingly.
|
||||
/// @returns false if the amount of bytes read is lager than 0xffff
|
||||
bool accessMemory(dev::u256 const& _offset, dev::u256 const& _size = 32);
|
||||
/// @returns the memory contents at the provided address.
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
dev::bytes readMemory(dev::u256 const& _offset, dev::u256 const& _size = 32);
|
||||
/// @returns the memory contents at the provided address.
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
dev::u256 readMemoryWord(dev::u256 const& _offset);
|
||||
/// @returns writes a word to memory
|
||||
/// Does not adjust msize, use @a accessMemory for that
|
||||
void writeMemoryWord(dev::u256 const& _offset, dev::u256 const& _value);
|
||||
|
||||
void logTrace(dev::eth::Instruction _instruction, std::vector<dev::u256> const& _arguments = {}, dev::bytes const& _data = {});
|
||||
/// Appends a log to the trace representing an instruction or similar operation by string,
|
||||
|
@ -47,13 +47,12 @@ void InterpreterState::dumpTraceAndState(ostream& _out) const
|
||||
for (auto const& line: trace)
|
||||
_out << " " << line << endl;
|
||||
_out << "Memory dump:\n";
|
||||
for (size_t i = 0; i < memory.size(); i += 0x20)
|
||||
{
|
||||
bytesConstRef data(memory.data() + i, 0x20);
|
||||
if (boost::algorithm::all_of_equal(data, 0))
|
||||
continue;
|
||||
_out << " " << std::hex << std::setw(4) << i << ": " << toHex(data.toBytes()) << endl;
|
||||
}
|
||||
map<u256, u256> words;
|
||||
for (auto const& [offset, value]: memory)
|
||||
words[(offset / 0x20) * 0x20] |= u256(uint32_t(value)) << (256 - 8 - 8 * size_t(offset % 0x20));
|
||||
for (auto const& [offset, value]: words)
|
||||
if (value != 0)
|
||||
_out << " " << std::hex << std::setw(4) << offset << ": " << h256(value).hex() << endl;
|
||||
_out << "Storage dump:" << endl;
|
||||
for (auto const& slot: storage)
|
||||
if (slot.second != h256(0))
|
||||
@ -90,7 +89,8 @@ void Interpreter::operator()(VariableDeclaration const& _declaration)
|
||||
YulString varName = _declaration.variables.at(i).name;
|
||||
solAssert(!m_variables.count(varName), "");
|
||||
m_variables[varName] = values.at(i);
|
||||
m_scopes.back().insert(varName);
|
||||
solAssert(!m_scopes.back().count(varName), "");
|
||||
m_scopes.back().emplace(varName, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,8 +164,8 @@ void Interpreter::operator()(Block const& _block)
|
||||
if (statement.type() == typeid(FunctionDefinition))
|
||||
{
|
||||
FunctionDefinition const& funDef = boost::get<FunctionDefinition>(statement);
|
||||
m_functions[funDef.name] = &funDef;
|
||||
m_scopes.back().insert(funDef.name);
|
||||
solAssert(!m_scopes.back().count(funDef.name), "");
|
||||
m_scopes.back().emplace(funDef.name, &funDef);
|
||||
}
|
||||
|
||||
for (auto const& statement: _block.statements)
|
||||
@ -180,25 +180,23 @@ void Interpreter::operator()(Block const& _block)
|
||||
|
||||
u256 Interpreter::evaluate(Expression const& _expression)
|
||||
{
|
||||
ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions, m_scopes);
|
||||
ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_scopes);
|
||||
ev.visit(_expression);
|
||||
return ev.value();
|
||||
}
|
||||
|
||||
vector<u256> Interpreter::evaluateMulti(Expression const& _expression)
|
||||
{
|
||||
ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_functions, m_scopes);
|
||||
ExpressionEvaluator ev(m_state, m_dialect, m_variables, m_scopes);
|
||||
ev.visit(_expression);
|
||||
return ev.values();
|
||||
}
|
||||
|
||||
void Interpreter::closeScope()
|
||||
{
|
||||
for (auto const& var: m_scopes.back())
|
||||
{
|
||||
size_t erased = m_variables.erase(var) + m_functions.erase(var);
|
||||
solAssert(erased == 1, "");
|
||||
}
|
||||
for (auto const& [var, funDeclaration]: m_scopes.back())
|
||||
if (!funDeclaration)
|
||||
solAssert(m_variables.erase(var) == 1, "");
|
||||
m_scopes.pop_back();
|
||||
}
|
||||
|
||||
@ -237,22 +235,21 @@ void ExpressionEvaluator::operator()(FunctionCall const& _funCall)
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(m_functions.count(_funCall.functionName.name), "");
|
||||
FunctionDefinition const& fun = *m_functions.at(_funCall.functionName.name);
|
||||
solAssert(m_values.size() == fun.parameters.size(), "");
|
||||
map<YulString, u256> variables;
|
||||
for (size_t i = 0; i < fun.parameters.size(); ++i)
|
||||
variables[fun.parameters.at(i).name] = m_values.at(i);
|
||||
for (size_t i = 0; i < fun.returnVariables.size(); ++i)
|
||||
variables[fun.returnVariables.at(i).name] = 0;
|
||||
auto [functionScopes, fun] = findFunctionAndScope(_funCall.functionName.name);
|
||||
|
||||
// TODO function name lookup could be a little more efficient,
|
||||
// we have to copy the list here.
|
||||
Interpreter interpreter(m_state, m_dialect, variables, visibleFunctionsFor(fun.name));
|
||||
interpreter(fun.body);
|
||||
solAssert(fun, "Function not found.");
|
||||
solAssert(m_values.size() == fun->parameters.size(), "");
|
||||
map<YulString, u256> variables;
|
||||
for (size_t i = 0; i < fun->parameters.size(); ++i)
|
||||
variables[fun->parameters.at(i).name] = m_values.at(i);
|
||||
for (size_t i = 0; i < fun->returnVariables.size(); ++i)
|
||||
variables[fun->returnVariables.at(i).name] = 0;
|
||||
|
||||
Interpreter interpreter(m_state, m_dialect, variables, functionScopes);
|
||||
interpreter(fun->body);
|
||||
|
||||
m_values.clear();
|
||||
for (auto const& retVar: fun.returnVariables)
|
||||
for (auto const& retVar: fun->returnVariables)
|
||||
m_values.emplace_back(interpreter.valueOfVariable(retVar.name));
|
||||
}
|
||||
|
||||
@ -281,19 +278,26 @@ void ExpressionEvaluator::evaluateArgs(vector<Expression> const& _expr)
|
||||
std::reverse(m_values.begin(), m_values.end());
|
||||
}
|
||||
|
||||
std::map<YulString, FunctionDefinition const*> ExpressionEvaluator::visibleFunctionsFor(YulString const& _name)
|
||||
pair<
|
||||
vector<map<YulString, FunctionDefinition const*>>,
|
||||
FunctionDefinition const*
|
||||
> ExpressionEvaluator::findFunctionAndScope(YulString _functionName) const
|
||||
{
|
||||
std::map<YulString, FunctionDefinition const*> functions;
|
||||
|
||||
FunctionDefinition const* fun = nullptr;
|
||||
std::vector<std::map<YulString, FunctionDefinition const*>> newScopes;
|
||||
for (auto const& scope: m_scopes)
|
||||
{
|
||||
for (auto const& symbol: scope)
|
||||
if (m_functions.count(symbol) > 0)
|
||||
functions[symbol] = m_functions.at(symbol);
|
||||
|
||||
if (scope.count(_name))
|
||||
// Copy over all functions.
|
||||
newScopes.push_back({});
|
||||
for (auto const& [name, funDef]: scope)
|
||||
if (funDef)
|
||||
newScopes.back().emplace(name, funDef);
|
||||
// Stop at the called function.
|
||||
if (scope.count(_functionName))
|
||||
{
|
||||
fun = scope.at(_functionName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return functions;
|
||||
return {move(newScopes), fun};
|
||||
}
|
||||
|
@ -64,8 +64,7 @@ struct InterpreterState
|
||||
{
|
||||
dev::bytes calldata;
|
||||
dev::bytes returndata;
|
||||
/// TODO turn this into "vector with holes" for the randomized testing
|
||||
dev::bytes memory;
|
||||
std::map<dev::u256, uint8_t> memory;
|
||||
/// This is different than memory.size() because we ignore gas.
|
||||
dev::u256 msize;
|
||||
std::map<dev::h256, dev::h256> storage;
|
||||
@ -86,9 +85,6 @@ struct InterpreterState
|
||||
std::vector<std::string> trace;
|
||||
/// This is actually an input parameter that more or less limits the runtime.
|
||||
size_t maxTraceSize = 0;
|
||||
/// Memory size limit. Anything beyond this will still work, but it has
|
||||
/// deterministic yet not necessarily consistent behaviour.
|
||||
size_t maxMemSize = 0x200;
|
||||
size_t maxSteps = 0;
|
||||
size_t numSteps = 0;
|
||||
LoopState loopState = LoopState::Default;
|
||||
@ -106,12 +102,12 @@ public:
|
||||
InterpreterState& _state,
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, dev::u256> _variables = {},
|
||||
std::map<YulString, FunctionDefinition const*> _functions = {}
|
||||
std::vector<std::map<YulString, FunctionDefinition const*>> _scopes = {}
|
||||
):
|
||||
m_dialect(_dialect),
|
||||
m_state(_state),
|
||||
m_variables(std::move(_variables)),
|
||||
m_functions(std::move(_functions))
|
||||
m_scopes(std::move(_scopes))
|
||||
{}
|
||||
|
||||
void operator()(ExpressionStatement const& _statement) override;
|
||||
@ -136,17 +132,17 @@ private:
|
||||
std::vector<dev::u256> evaluateMulti(Expression const& _expression);
|
||||
|
||||
void openScope() { m_scopes.push_back({}); }
|
||||
/// Unregisters variables.
|
||||
/// Unregisters variables and functions.
|
||||
void closeScope();
|
||||
|
||||
Dialect const& m_dialect;
|
||||
InterpreterState& m_state;
|
||||
/// Values of variables.
|
||||
std::map<YulString, dev::u256> m_variables;
|
||||
/// Meanings of functions.
|
||||
std::map<YulString, FunctionDefinition const*> m_functions;
|
||||
/// Scopes of variables and functions, used to clear them at end of blocks.
|
||||
std::vector<std::set<YulString>> m_scopes;
|
||||
/// Scopes of variables and functions. Used for lookup, clearing at end of blocks
|
||||
/// and passing over the visible functions across function calls.
|
||||
/// The pointer is nullptr if and only if the key is a variable.
|
||||
std::vector<std::map<YulString, FunctionDefinition const*>> m_scopes;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -159,13 +155,11 @@ public:
|
||||
InterpreterState& _state,
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, dev::u256> const& _variables,
|
||||
std::map<YulString, FunctionDefinition const*> const& _functions,
|
||||
std::vector<std::set<YulString>> const& _scopes
|
||||
std::vector<std::map<YulString, FunctionDefinition const*>> const& _scopes
|
||||
):
|
||||
m_state(_state),
|
||||
m_dialect(_dialect),
|
||||
m_variables(_variables),
|
||||
m_functions(_functions),
|
||||
m_scopes(_scopes)
|
||||
{}
|
||||
|
||||
@ -186,16 +180,19 @@ private:
|
||||
/// stores it in m_value.
|
||||
void evaluateArgs(std::vector<Expression> const& _expr);
|
||||
|
||||
/// Extracts functions from the earlier scopes that are visible for the given function
|
||||
std::map<YulString, FunctionDefinition const*> visibleFunctionsFor(YulString const& _name);
|
||||
/// Finds the function called @a _functionName in the current scope stack and returns
|
||||
/// the function's scope stack (with variables removed) and definition.
|
||||
std::pair<
|
||||
std::vector<std::map<YulString, FunctionDefinition const*>>,
|
||||
FunctionDefinition const*
|
||||
> findFunctionAndScope(YulString _functionName) const;
|
||||
|
||||
InterpreterState& m_state;
|
||||
Dialect const& m_dialect;
|
||||
/// Values of variables.
|
||||
std::map<YulString, dev::u256> const& m_variables;
|
||||
/// Meanings of functions.
|
||||
std::map<YulString, FunctionDefinition const*> const& m_functions;
|
||||
std::vector<std::set<YulString>> const& m_scopes;
|
||||
/// Stack of scopes in the current context.
|
||||
std::vector<std::map<YulString, FunctionDefinition const*>> const& m_scopes;
|
||||
/// Current value of the expression
|
||||
std::vector<dev::u256> m_values;
|
||||
};
|
||||
|
@ -87,7 +87,6 @@ void interpret(string const& _source)
|
||||
|
||||
InterpreterState state;
|
||||
state.maxTraceSize = 10000;
|
||||
state.maxMemSize = 0x20000000;
|
||||
Dialect const& dialect(EVMDialect::strictAssemblyForEVMObjects(langutil::EVMVersion{}));
|
||||
Interpreter interpreter(state, dialect);
|
||||
try
|
||||
|
Loading…
Reference in New Issue
Block a user