Merge pull request #7326 from ethereum/develop

Merge develop into 0.6.0 branch.
This commit is contained in:
chriseth 2019-09-02 16:11:20 +02:00 committed by GitHub
commit c499758cd8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1470 additions and 208 deletions

View File

@ -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
View 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:

View File

@ -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:

View File

@ -41,15 +41,11 @@ become the new richest.
mostSent = msg.value;
}
function becomeRichest() public payable returns (bool) {
if (msg.value > mostSent) {
function becomeRichest() public payable {
require(msg.value > mostSent, "Not enough money sent.");
pendingWithdrawals[richest] += msg.value;
richest = msg.sender;
mostSent = msg.value;
return true;
} else {
return false;
}
}
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) {
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;
return true;
} else {
return false;
}
}
}

View File

@ -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,

View File

@ -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(),

View File

@ -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

View File

@ -2,7 +2,7 @@
"extends": "solhint:default",
"plugins": [],
"rules": {
"compiler-fixed": false,
"no-inline-assembly": false
"compiler-fixed": "off",
"no-inline-assembly": "off"
}
}

View File

@ -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."

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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();

View File

@ -313,13 +313,17 @@ 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{}});
/// 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;

View File

@ -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.

View File

@ -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
);

View File

@ -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
{

View 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

View 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

View File

@ -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))
// }

View File

@ -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

View File

@ -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_";

View File

@ -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
*

View File

@ -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;
};
}
}

View File

@ -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);

View File

@ -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;
};
}
}

View 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"
};

View File

@ -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);

View File

@ -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,

View File

@ -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};
}

View File

@ -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;
};

View File

@ -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