Merge pull request #10013 from ethereum/errorCodesPanic

Panic with error codes.
This commit is contained in:
chriseth 2020-10-22 19:38:27 +02:00 committed by GitHub
commit f22cb64710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
123 changed files with 803 additions and 477 deletions

View File

@ -7,6 +7,7 @@ Breaking Changes:
* Type System: Unary negation can only be used on signed integers, not on unsigned integers. * Type System: Unary negation can only be used on signed integers, not on unsigned integers.
* Type System: Disallow explicit conversions from negative literals and literals larger than ``type(uint160).max`` to ``address`` type. * Type System: Disallow explicit conversions from negative literals and literals larger than ``type(uint160).max`` to ``address`` type.
* Parser: Exponentiation is right associative. ``a**b**c`` is parsed as ``a**(b**c)``. * Parser: Exponentiation is right associative. ``a**b**c`` is parsed as ``a**(b**c)``.
* Code Generator: Use ``revert`` with error signature ``Panic(uint256)`` and error codes instead of invalid opcode on failing assertions.
Language Features: Language Features:

View File

@ -18,6 +18,15 @@ and it does something else afterwards.
* Exponentiation is right associative, i.e., the expression ``a**b**c`` is parsed as ``a**(b**c)``. * Exponentiation is right associative, i.e., the expression ``a**b**c`` is parsed as ``a**(b**c)``.
Before 0.8.0, it was parsed as ``(a**b)**c``. Before 0.8.0, it was parsed as ``(a**b)**c``.
Semantic only Changes
=====================
* Failing assertions (and other internal checks like division by zero) do not use the invalid opcode anymore but instead revert
with error data equal to a function call to ``Panic(uint256)`` with an error code specific to the circumstances.
This will save gas on errors while it still allows static analysis tools to detect these situations.
Syntactic Only Changes Syntactic Only Changes
====================== ======================

View File

@ -564,35 +564,53 @@ of an exception instead of "bubbling up".
Exceptions can be caught with the ``try``/``catch`` statement. Exceptions can be caught with the ``try``/``catch`` statement.
``assert`` and ``require`` Exceptions can contain data that is passed back to the caller.
-------------------------- This data consists of a 4-byte selector and subsequent :ref:`ABI-encoded<abi>` data.
The selector is computed in the same way as a function selector, i.e.,
the first four bytes of the keccak256-hash of a function
signature - in this case an error signature.
Currently, Solidity supports two error signatures: ``Error(string)``
and ``Panic(uint256)``. The first ("error") is used for "regular" error conditions
while the second ("panic") is used for errors that should not be present in bug-free code.
Panic via ``assert`` and Error via ``require``
----------------------------------------------
The convenience functions ``assert`` and ``require`` can be used to check for conditions and throw an exception The convenience functions ``assert`` and ``require`` can be used to check for conditions and throw an exception
if the condition is not met. if the condition is not met.
The ``assert`` function should only be used to test for internal The ``assert`` function creates an error of type ``Panic(uint256)``.
The same error is created by the compiler in certain situations as listed below.
Assert should only be used to test for internal
errors, and to check invariants. Properly functioning code should errors, and to check invariants. Properly functioning code should
never reach a failing ``assert`` statement; if this happens there never create a Panic, not even on invalid external input.
If this happens, then there
is a bug in your contract which you should fix. Language analysis is a bug in your contract which you should fix. Language analysis
tools can evaluate your contract to identify the conditions and tools can evaluate your contract to identify the conditions and
function calls which will reach a failing ``assert``. function calls which will cause a Panic.
An ``assert``-style exception is generated in the following situations: A Panic exception is generated in the following situations.
The error code supplied with the error data indicates the kind of panic.
#. If you access an array or an array slice at a too large or negative index (i.e. ``x[i]`` where ``i >= x.length`` or ``i < 0``). #. 0x01: If you call ``assert`` with an argument that evaluates to false.
#. If you access a fixed-length ``bytesN`` at a too large or negative index. #. 0x11: If an arithmetic operation results in underflow or overflow outside of an ``unchecked { ... }`` block.
#. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``). #. 0x12; If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
#. If an arithmetic operation results in under- or overflow outside of an ``unchecked { ... }`` block. #. 0x21: If you convert a value that is too big or negative into an enum type.
#. If you convert a value too big or negative into an enum type. #. 0x31: If you call ``.pop()`` on an empty array.
#. If you call a zero-initialized variable of internal function type. #. 0x32: If you access an array, ``bytesN`` or an array slice at an out-of-bounds or negative index (i.e. ``x[i]`` where ``i >= x.length`` or ``i < 0``).
#. If you call ``assert`` with an argument that evaluates to false. #. 0x41: If you allocate too much memory or create an array that is too large.
#. 0x51: If you call a zero-initialized variable of internal function type.
The ``require`` function should be used to ensure valid conditions The ``require`` function either creates an error of type ``Error(string)``
or an error without any error data and it
should be used to ensure valid conditions
that cannot be detected until execution time. that cannot be detected until execution time.
This includes conditions on inputs This includes conditions on inputs
or return values from calls to external contracts. or return values from calls to external contracts.
A ``require``-style exception is generated in the following situations: A ``Error(string)`` exception is generated in the following situations:
#. Calling ``require`` with an argument that evaluates to ``false``. #. Calling ``require`` with an argument that evaluates to ``false``.
#. If you call a function via a message call but it does not finish #. If you call a function via a message call but it does not finish
@ -611,6 +629,11 @@ A ``require``-style exception is generated in the following situations:
You can optionally provide a message string for ``require``, but not for ``assert``. You can optionally provide a message string for ``require``, but not for ``assert``.
.. note::
If you do not provide a string argument to ``require``, it will revert
with empty error data, not even including the error selector.
The following example shows how you can use ``require`` to check conditions on inputs The following example shows how you can use ``require`` to check conditions on inputs
and ``assert`` for internal error checking. and ``assert`` for internal error checking.
@ -633,29 +656,29 @@ and ``assert`` for internal error checking.
} }
Internally, Solidity performs a revert operation (instruction Internally, Solidity performs a revert operation (instruction
``0xfd``) for a ``require``-style exception and executes an invalid operation ``0xfd``). This causes
(instruction ``0xfe``) to throw an ``assert``-style exception. In both cases, this causes
the EVM to revert all changes made to the state. The reason for reverting the EVM to revert all changes made to the state. The reason for reverting
is that there is no safe way to continue execution, because an expected effect is that there is no safe way to continue execution, because an expected effect
did not occur. Because we want to keep the atomicity of transactions, the did not occur. Because we want to keep the atomicity of transactions, the
safest action is to revert all changes and make the whole transaction safest action is to revert all changes and make the whole transaction
(or at least call) without effect. (or at least call) without effect.
In both cases, the caller can react on such failures using ``try``/``catch`` In both cases, the caller can react on such failures using ``try``/``catch``, but
(in the failing ``assert``-style exception only if enough gas is left), but
the changes in the caller will always be reverted. the changes in the caller will always be reverted.
.. note:: .. note::
``assert``-style exceptions consume all gas available to the call, Panic exceptions used to use the ``invalid`` opcode before Solidity 0.8.0,
while ``require``-style exceptions do not consume any gas starting from the Metropolis release. which consumed all gas available to the call.
Exceptions that use ``require`` used to consume all gas until before the Metropolis release.
``revert`` ``revert``
---------- ----------
The ``revert`` function is another way to trigger exceptions from within other code blocks to flag an error and The ``revert`` function is another way to trigger exceptions from within other code blocks to flag an error and
revert the current call. The function takes an optional string revert the current call. The function takes an optional string
message containing details about the error that is passed back to the caller. message containing details about the error that is passed back to the caller
and it will create an ``Error(string)`` exception.
The following example shows how to use an error string together with ``revert`` and the equivalent ``require``: The following example shows how to use an error string together with ``revert`` and the equivalent ``require``:
@ -726,9 +749,7 @@ A failure in an external call can be caught using a try/catch statement, as foll
errorCount++; errorCount++;
return (0, false); return (0, false);
} catch (bytes memory /*lowLevelData*/) { } catch (bytes memory /*lowLevelData*/) {
// This is executed in case revert() was used // This is executed in case revert() was used.
// or there was a failing assertion, division
// by zero, etc. inside getData.
errorCount++; errorCount++;
return (0, false); return (0, false);
} }
@ -754,9 +775,8 @@ It is planned to support other types of error data in the future.
The string ``Error`` is currently parsed as is and is not treated as an identifier. The string ``Error`` is currently parsed as is and is not treated as an identifier.
The clause ``catch (bytes memory lowLevelData)`` is executed if the error signature The clause ``catch (bytes memory lowLevelData)`` is executed if the error signature
does not match any other clause, there was an error during decoding of the error does not match any other clause, if there was an error while decoding the error
message, if there was a failing assertion in the external message, or
call (for example due to a division by zero or a failing ``assert()``) or
if no error data was provided with the exception. if no error data was provided with the exception.
The declared variable provides access to the low-level error data in that case. The declared variable provides access to the low-level error data in that case.

View File

@ -107,7 +107,7 @@ Note that in contrast, division on :ref:`literals<rational_literals>` results in
of arbitrary precision. of arbitrary precision.
.. note:: .. note::
Division by zero causes a failing assert. This check can **not** be disabled through ``unchecked { ... }``. Division by zero causes a :ref:`Panic error<assert-and-require>`. This check can **not** be disabled through ``unchecked { ... }``.
.. note:: .. note::
The expression ``type(int).min / (-1)`` is the only case where division causes an overflow. The expression ``type(int).min / (-1)`` is the only case where division causes an overflow.
@ -127,7 +127,7 @@ results in the same sign as its left operand (or zero) and ``a % n == -(-a % n)`
* ``int256(-5) % int256(-2) == int256(-1)`` * ``int256(-5) % int256(-2) == int256(-1)``
.. note:: .. note::
Modulo with zero causes a failing assert. This check can **not** be disabled through ``unchecked { ... }``. Modulo with zero causes a :ref:`Panic error<assert-and-require>`. This check can **not** be disabled through ``unchecked { ... }``.
Exponentiation Exponentiation
^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^
@ -562,7 +562,8 @@ Enums
Enums are one way to create a user-defined type in Solidity. They are explicitly convertible Enums are one way to create a user-defined type in Solidity. They are explicitly convertible
to and from all integer types but implicit conversion is not allowed. The explicit conversion to and from all integer types but implicit conversion is not allowed. The explicit conversion
from integer checks at runtime that the value lies inside the range of the enum and causes a failing assert otherwise. from integer checks at runtime that the value lies inside the range of the enum and causes a
:ref:`Panic error<assert-and-require>` otherwise.
Enums require at least one member, and its default value when declared is the first member. Enums require at least one member, and its default value when declared is the first member.
The data representation is the same as for enums in C: The options are represented by The data representation is the same as for enums in C: The options are represented by
@ -656,7 +657,7 @@ On the other hand, a ``non-payable`` function will reject Ether sent to it,
so ``non-payable`` functions cannot be converted to ``payable`` functions. so ``non-payable`` functions cannot be converted to ``payable`` functions.
If a function type variable is not initialised, calling it results If a function type variable is not initialised, calling it results
in a failed assertion. The same happens if you call a function after using ``delete`` in a :ref:`Panic error<assert-and-require>`. The same happens if you call a function after using ``delete``
on it. on it.
If external function types are used outside of the context of Solidity, If external function types are used outside of the context of Solidity,

View File

@ -144,7 +144,7 @@ See the dedicated section on :ref:`assert and require<assert-and-require>` for
more details on error handling and when to use which function. more details on error handling and when to use which function.
``assert(bool condition)`` ``assert(bool condition)``
causes an invalid opcode and thus state change reversion if the condition is not met - to be used for internal errors. causes a Panic error and thus state change reversion if the condition is not met - to be used for internal errors.
``require(bool condition)`` ``require(bool condition)``
reverts if the condition is not met - to be used for errors in inputs or external components. reverts if the condition is not met - to be used for errors in inputs or external components.

View File

@ -29,6 +29,9 @@
#include <libsolidity/codegen/CompilerUtils.h> #include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/codegen/LValue.h> #include <libsolidity/codegen/LValue.h>
#include <libsolutil/FunctionSelector.h>
#include <libsolutil/Whiskers.h>
#include <libevmasm/Instruction.h> #include <libevmasm/Instruction.h>
#include <liblangutil/Exceptions.h> #include <liblangutil/Exceptions.h>
@ -857,13 +860,17 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
if (_type.isByteArray()) if (_type.isByteArray())
{ {
m_context.appendInlineAssembly(R"({ util::Whiskers code(R"({
let slot_value := sload(ref) let slot_value := sload(ref)
switch and(slot_value, 1) switch and(slot_value, 1)
case 0 { case 0 {
// short byte array // short byte array
let length := and(div(slot_value, 2), 0x1f) let length := and(div(slot_value, 2), 0x1f)
if iszero(length) { invalid() } if iszero(length) {
mstore(0, <panicSelector>)
mstore(4, <emptyArrayPop>)
revert(0, 0x24)
}
// Zero-out the suffix including the least significant byte. // Zero-out the suffix including the least significant byte.
let mask := sub(exp(0x100, sub(33, length)), 1) let mask := sub(exp(0x100, sub(33, length)), 1)
@ -901,7 +908,10 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
sstore(ref, slot_value) sstore(ref, slot_value)
} }
} }
})", {"ref"}); })");
code("panicSelector", util::selectorFromSignature("Panic(uint256)").str());
code("emptyArrayPop", to_string(unsigned(util::PanicCode::EmptyArrayPop)));
m_context.appendInlineAssembly(code.render(), {"ref"});
m_context << Instruction::POP; m_context << Instruction::POP;
} }
else else
@ -912,7 +922,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
m_context << Instruction::DUP1; m_context << Instruction::DUP1;
// stack: ArrayReference oldLength oldLength // stack: ArrayReference oldLength oldLength
m_context << Instruction::ISZERO; m_context << Instruction::ISZERO;
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::EmptyArrayPop);
// Stack: ArrayReference oldLength // Stack: ArrayReference oldLength
m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB; m_context << u256(1) << Instruction::SWAP1 << Instruction::SUB;
@ -1058,7 +1068,7 @@ void ArrayUtils::accessIndex(ArrayType const& _arrayType, bool _doBoundsCheck, b
// check out-of-bounds access // check out-of-bounds access
m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO;
// out-of-bounds access throws exception // out-of-bounds access throws exception
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::ArrayOutOfBounds);
} }
if (location == DataLocation::CallData && _arrayType.isDynamicallySized()) if (location == DataLocation::CallData && _arrayType.isDynamicallySized())
// remove length if present // remove length if present

View File

@ -72,7 +72,7 @@ public:
/// Stack pre: reference (excludes byte offset) /// Stack pre: reference (excludes byte offset)
/// Stack post: new_length /// Stack post: new_length
void incrementDynamicArraySize(ArrayType const& _type) const; void incrementDynamicArraySize(ArrayType const& _type) const;
/// Decrements the size of a dynamic array by one if length is nonzero. Causes an invalid instruction otherwise. /// Decrements the size of a dynamic array by one if length is nonzero. Causes a Panic otherwise.
/// Clears the removed data element. In case of a byte array, this might move the data. /// Clears the removed data element. In case of a byte array, this might move the data.
/// Stack pre: reference /// Stack pre: reference
/// Stack post: /// Stack post:

View File

@ -41,6 +41,7 @@
#include <libyul/Utilities.h> #include <libyul/Utilities.h>
#include <libsolutil/Whiskers.h> #include <libsolutil/Whiskers.h>
#include <libsolutil/FunctionSelector.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <liblangutil/Scanner.h> #include <liblangutil/Scanner.h>
@ -330,16 +331,24 @@ CompilerContext& CompilerContext::appendJump(evmasm::AssemblyItem::JumpType _jum
return *this << item; return *this << item;
} }
CompilerContext& CompilerContext::appendInvalid() CompilerContext& CompilerContext::appendPanic(util::PanicCode _code)
{ {
return *this << Instruction::INVALID; Whiskers templ(R"({
mstore(0, <selector>)
mstore(4, <code>)
revert(0, 0x24)
})");
templ("selector", util::selectorFromSignature("Panic(uint256)").str());
templ("code", u256(_code).str());
appendInlineAssembly(templ.render());
return *this;
} }
CompilerContext& CompilerContext::appendConditionalInvalid() CompilerContext& CompilerContext::appendConditionalPanic(util::PanicCode _code)
{ {
*this << Instruction::ISZERO; *this << Instruction::ISZERO;
evmasm::AssemblyItem afterTag = appendConditionalJump(); evmasm::AssemblyItem afterTag = appendConditionalJump();
*this << Instruction::INVALID; appendPanic(_code);
*this << afterTag; *this << afterTag;
return *this; return *this;
} }

View File

@ -36,6 +36,7 @@
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <liblangutil/EVMVersion.h> #include <liblangutil/EVMVersion.h>
#include <libsolutil/Common.h> #include <libsolutil/Common.h>
#include <libsolutil/ErrorCodes.h>
#include <libyul/AsmAnalysisInfo.h> #include <libyul/AsmAnalysisInfo.h>
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
@ -195,10 +196,10 @@ public:
evmasm::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); } evmasm::AssemblyItem appendJumpToNew() { return m_asm->appendJump().tag(); }
/// Appends a JUMP to a tag already on the stack /// Appends a JUMP to a tag already on the stack
CompilerContext& appendJump(evmasm::AssemblyItem::JumpType _jumpType = evmasm::AssemblyItem::JumpType::Ordinary); CompilerContext& appendJump(evmasm::AssemblyItem::JumpType _jumpType = evmasm::AssemblyItem::JumpType::Ordinary);
/// Appends an INVALID instruction /// Appends code to revert with a Panic(uint256) error.
CompilerContext& appendInvalid(); CompilerContext& appendPanic(util::PanicCode _code);
/// Appends a conditional INVALID instruction /// Appends code to revert with a Panic(uint256) error if the topmost stack element is nonzero.
CompilerContext& appendConditionalInvalid(); CompilerContext& appendConditionalPanic(util::PanicCode _code);
/// Appends a REVERT(0, 0) call /// Appends a REVERT(0, 0) call
/// @param _message is an optional revert message used in debug mode /// @param _message is an optional revert message used in debug mode
CompilerContext& appendRevert(std::string const& _message = ""); CompilerContext& appendRevert(std::string const& _message = "");

View File

@ -810,7 +810,7 @@ void CompilerUtils::convertType(
if (_asPartOfArgumentDecoding) if (_asPartOfArgumentDecoding)
m_context.appendConditionalRevert(false, "Enum out of range"); m_context.appendConditionalRevert(false, "Enum out of range");
else else
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::EnumConversionError);
enumOverflowCheckPending = false; enumOverflowCheckPending = false;
} }
break; break;
@ -849,7 +849,7 @@ void CompilerUtils::convertType(
EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType); EnumType const& enumType = dynamic_cast<decltype(enumType)>(_targetType);
solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error."); solAssert(enumType.numberOfMembers() > 0, "empty enum should have caused a parser error.");
m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT; m_context << u256(enumType.numberOfMembers() - 1) << Instruction::DUP2 << Instruction::GT;
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::EnumConversionError);
enumOverflowCheckPending = false; enumOverflowCheckPending = false;
} }
else if (targetTypeCategory == Type::Category::FixedPoint) else if (targetTypeCategory == Type::Category::FixedPoint)
@ -1213,13 +1213,13 @@ void CompilerUtils::pushZeroValue(Type const& _type)
if (funType->kind() == FunctionType::Kind::Internal) if (funType->kind() == FunctionType::Kind::Internal)
{ {
m_context << m_context.lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) { m_context << m_context.lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) {
_context.appendInvalid(); _context.appendPanic(util::PanicCode::InvalidInternalFunction);
}); });
if (CompilerContext* runCon = m_context.runtimeContext()) if (CompilerContext* runCon = m_context.runtimeContext())
{ {
leftShiftNumberOnStack(32); leftShiftNumberOnStack(32);
m_context << runCon->lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) { m_context << runCon->lowLevelFunctionTag("$invalidFunction", 0, 0, [](CompilerContext& _context) {
_context.appendInvalid(); _context.appendPanic(util::PanicCode::InvalidInternalFunction);
}).toSubAssemblyTag(m_context.runtimeSub()); }).toSubAssemblyTag(m_context.runtimeSub());
m_context << Instruction::OR; m_context << Instruction::OR;
} }

View File

@ -47,6 +47,7 @@
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <libsolutil/Whiskers.h> #include <libsolutil/Whiskers.h>
#include <libsolutil/FunctionSelector.h>
#include <boost/range/adaptor/reversed.hpp> #include <boost/range/adaptor/reversed.hpp>
@ -229,19 +230,26 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
m_context.pushSubroutineSize(m_context.runtimeSub()); m_context.pushSubroutineSize(m_context.runtimeSub());
m_context.pushSubroutineOffset(m_context.runtimeSub()); m_context.pushSubroutineOffset(m_context.runtimeSub());
// This code replaces the address added by appendDeployTimeAddress(). // This code replaces the address added by appendDeployTimeAddress().
m_context.appendInlineAssembly(R"( m_context.appendInlineAssembly(
{ Whiskers(R"(
// If code starts at 11, an mstore(0) writes to the full PUSH20 plus data {
// without the need for a shift. // If code starts at 11, an mstore(0) writes to the full PUSH20 plus data
let codepos := 11 // without the need for a shift.
codecopy(codepos, subOffset, subSize) let codepos := 11
// Check that the first opcode is a PUSH20 codecopy(codepos, subOffset, subSize)
if iszero(eq(0x73, byte(0, mload(codepos)))) { invalid() } // Check that the first opcode is a PUSH20
mstore(0, address()) if iszero(eq(0x73, byte(0, mload(codepos)))) {
mstore8(codepos, 0x73) mstore(0, <panicSig>)
return(codepos, subSize) mstore(4, 0)
} revert(0, 0x24)
)", {"subSize", "subOffset"}); }
mstore(0, address())
mstore8(codepos, 0x73)
return(codepos, subSize)
}
)")("panicSig", util::selectorFromSignature("Panic(uint256)").str()).render(),
{"subSize", "subOffset"}
);
return m_context.runtimeSub(); return m_context.runtimeSub();
} }

View File

@ -933,7 +933,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{ {
acceptAndConvert(*arguments[2], *TypeProvider::uint256()); acceptAndConvert(*arguments[2], *TypeProvider::uint256());
m_context << Instruction::DUP1 << Instruction::ISZERO; m_context << Instruction::DUP1 << Instruction::ISZERO;
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::DivisionByZero);
for (unsigned i = 1; i < 3; i ++) for (unsigned i = 1; i < 3; i ++)
acceptAndConvert(*arguments[2 - i], *TypeProvider::uint256()); acceptAndConvert(*arguments[2 - i], *TypeProvider::uint256());
if (function.kind() == FunctionType::Kind::AddMod) if (function.kind() == FunctionType::Kind::AddMod)
@ -1051,7 +1051,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
m_context << u256(0xffffffffffffffff); m_context << u256(0xffffffffffffffff);
m_context << Instruction::DUP2; m_context << Instruction::DUP2;
m_context << Instruction::GT; m_context << Instruction::GT;
m_context.appendConditionalRevert(); m_context.appendConditionalPanic(PanicCode::ResourceError);
// Stack: requested_length // Stack: requested_length
utils().fetchFreeMemoryPointer(); utils().fetchFreeMemoryPointer();
@ -1121,7 +1121,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
auto success = m_context.appendConditionalJump(); auto success = m_context.appendConditionalJump();
if (function.kind() == FunctionType::Kind::Assert) if (function.kind() == FunctionType::Kind::Assert)
// condition was not met, flag an error // condition was not met, flag an error
m_context.appendInvalid(); m_context.appendPanic(util::PanicCode::Assert);
else if (haveReasonString) else if (haveReasonString)
{ {
utils().revertWithStringData(*arguments.at(1)->annotation().type); utils().revertWithStringData(*arguments.at(1)->annotation().type);
@ -1886,7 +1886,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
m_context << u256(fixedBytesType.numBytes()); m_context << u256(fixedBytesType.numBytes());
m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO; m_context << Instruction::DUP2 << Instruction::LT << Instruction::ISZERO;
// out-of-bounds access throws exception // out-of-bounds access throws exception
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::ArrayOutOfBounds);
m_context << Instruction::BYTE; m_context << Instruction::BYTE;
utils().leftShiftNumberOnStack(256 - 8); utils().leftShiftNumberOnStack(256 - 8);
@ -2154,7 +2154,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token _operator, Type cons
{ {
// Test for division by zero // Test for division by zero
m_context << Instruction::DUP2 << Instruction::ISZERO; m_context << Instruction::DUP2 << Instruction::ISZERO;
m_context.appendConditionalInvalid(); m_context.appendConditionalPanic(util::PanicCode::DivisionByZero);
if (_operator == Token::Div) if (_operator == Token::Div)
m_context << (c_isSigned ? Instruction::SDIV : Instruction::DIV); m_context << (c_isSigned ? Instruction::SDIV : Instruction::DIV);

View File

@ -122,7 +122,7 @@ string YulUtilFunctions::requireOrAssertFunction(bool _assert, Type const* _mess
if iszero(condition) { <error> } if iszero(condition) { <error> }
} }
)") )")
("error", _assert ? panicFunction() + "()" : "revert(0, 0)") ("error", _assert ? panicFunction(PanicCode::Assert) + "()" : "revert(0, 0)")
("functionName", functionName) ("functionName", functionName)
.render(); .render();
@ -478,7 +478,7 @@ string YulUtilFunctions::overflowCheckedIntAddFunction(IntegerType const& _type)
("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue())))
("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue())))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
.render(); .render();
}); });
} }
@ -530,7 +530,7 @@ string YulUtilFunctions::overflowCheckedIntMulFunction(IntegerType const& _type)
("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue())))
("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue())))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
.render(); .render();
}); });
} }
@ -560,13 +560,13 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type)
function <functionName>(x, y) -> r { function <functionName>(x, y) -> r {
x := <cleanupFunction>(x) x := <cleanupFunction>(x)
y := <cleanupFunction>(y) y := <cleanupFunction>(y)
if iszero(y) { <panic>() } if iszero(y) { <panicDivZero>() }
<?signed> <?signed>
// overflow for minVal / -1 // overflow for minVal / -1
if and( if and(
eq(x, <minVal>), eq(x, <minVal>),
eq(y, sub(0, 1)) eq(y, sub(0, 1))
) { <panic>() } ) { <panicOverflow>() }
</signed> </signed>
r := <?signed>s</signed>div(x, y) r := <?signed>s</signed>div(x, y)
} }
@ -575,7 +575,8 @@ string YulUtilFunctions::overflowCheckedIntDivFunction(IntegerType const& _type)
("signed", _type.isSigned()) ("signed", _type.isSigned())
("minVal", toCompactHexWithPrefix(u256(_type.minValue()))) ("minVal", toCompactHexWithPrefix(u256(_type.minValue())))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("panic", panicFunction()) ("panicDivZero", panicFunction(PanicCode::DivisionByZero))
("panicOverflow", panicFunction(PanicCode::UnderOverflow))
.render(); .render();
}); });
} }
@ -596,7 +597,7 @@ string YulUtilFunctions::wrappingIntDivFunction(IntegerType const& _type)
("functionName", functionName) ("functionName", functionName)
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("signed", _type.isSigned()) ("signed", _type.isSigned())
("error", panicFunction()) ("error", panicFunction(PanicCode::DivisionByZero))
.render(); .render();
}); });
} }
@ -617,7 +618,7 @@ string YulUtilFunctions::intModFunction(IntegerType const& _type)
("functionName", functionName) ("functionName", functionName)
("signed", _type.isSigned()) ("signed", _type.isSigned())
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::DivisionByZero))
.render(); .render();
}); });
} }
@ -647,7 +648,7 @@ string YulUtilFunctions::overflowCheckedIntSubFunction(IntegerType const& _type)
("maxValue", toCompactHexWithPrefix(u256(_type.maxValue()))) ("maxValue", toCompactHexWithPrefix(u256(_type.maxValue())))
("minValue", toCompactHexWithPrefix(u256(_type.minValue()))) ("minValue", toCompactHexWithPrefix(u256(_type.minValue())))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
.render(); .render();
}); });
} }
@ -808,7 +809,7 @@ string YulUtilFunctions::overflowCheckedIntLiteralExpFunction(
("exponentCleanupFunction", cleanupFunction(_exponentType)) ("exponentCleanupFunction", cleanupFunction(_exponentType))
("needsOverflowCheck", needsOverflowCheck) ("needsOverflowCheck", needsOverflowCheck)
("exponentUpperbound", to_string(exponentUpperbound)) ("exponentUpperbound", to_string(exponentUpperbound))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
("base", bigint2u(baseValue).str()) ("base", bigint2u(baseValue).str())
.render(); .render();
}); });
@ -866,7 +867,7 @@ string YulUtilFunctions::overflowCheckedUnsignedExpFunction()
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
("expLoop", overflowCheckedExpLoopFunction()) ("expLoop", overflowCheckedExpLoopFunction())
("shr_1", shiftRightFunction(1)) ("shr_1", shiftRightFunction(1))
.render(); .render();
@ -916,7 +917,7 @@ string YulUtilFunctions::overflowCheckedSignedExpFunction()
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
("expLoop", overflowCheckedExpLoopFunction()) ("expLoop", overflowCheckedExpLoopFunction())
("shr_1", shiftRightFunction(1)) ("shr_1", shiftRightFunction(1))
.render(); .render();
@ -957,7 +958,7 @@ string YulUtilFunctions::overflowCheckedExpLoopFunction()
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
("shr_1", shiftRightFunction(1)) ("shr_1", shiftRightFunction(1))
.render(); .render();
}); });
@ -1087,7 +1088,7 @@ std::string YulUtilFunctions::resizeDynamicArrayFunction(ArrayType const& _type)
} }
})") })")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ResourceError))
("fetchLength", arrayLengthFunction(_type)) ("fetchLength", arrayLengthFunction(_type))
("convertToSize", arrayConvertLengthToSize(_type)) ("convertToSize", arrayConvertLengthToSize(_type))
("dataPosition", arrayDataAreaFunction(_type)) ("dataPosition", arrayDataAreaFunction(_type))
@ -1123,7 +1124,7 @@ string YulUtilFunctions::resizeDynamicByteArrayFunction(ArrayType const& _type)
} }
})") })")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ResourceError))
("extractLength", extractByteArrayLengthFunction()) ("extractLength", extractByteArrayLengthFunction())
("maxArrayLength", (u256(1) << 64).str()) ("maxArrayLength", (u256(1) << 64).str())
("decreaseSize", decreaseByteArraySizeFunction(_type)) ("decreaseSize", decreaseByteArraySizeFunction(_type))
@ -1266,7 +1267,7 @@ string YulUtilFunctions::storageArrayPopFunction(ArrayType const& _type)
sstore(array, newLen) sstore(array, newLen)
})") })")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::EmptyArrayPop))
("fetchLength", arrayLengthFunction(_type)) ("fetchLength", arrayLengthFunction(_type))
("indexAccess", storageArrayIndexAccessFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type))
("setToZero", storageSetToZeroFunction(*_type.baseType())) ("setToZero", storageSetToZeroFunction(*_type.baseType()))
@ -1308,7 +1309,7 @@ string YulUtilFunctions::storageByteArrayPopFunction(ArrayType const& _type)
} }
})") })")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::EmptyArrayPop))
("extractByteArrayLength", extractByteArrayLengthFunction()) ("extractByteArrayLength", extractByteArrayLengthFunction())
("transitLongToShort", byteArrayTransitLongToShortFunction(_type)) ("transitLongToShort", byteArrayTransitLongToShortFunction(_type))
("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction()) ("encodeUsedSetLen", shortByteArrayEncodeUsedAreaSetLengthFunction())
@ -1370,7 +1371,7 @@ string YulUtilFunctions::storageArrayPushFunction(ArrayType const& _type)
</isByteArray> </isByteArray>
})") })")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ResourceError))
("extractByteArrayLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "") ("extractByteArrayLength", _type.isByteArray() ? extractByteArrayLengthFunction() : "")
("dataAreaFunction", arrayDataAreaFunction(_type)) ("dataAreaFunction", arrayDataAreaFunction(_type))
("isByteArray", _type.isByteArray()) ("isByteArray", _type.isByteArray())
@ -1400,7 +1401,7 @@ string YulUtilFunctions::storageArrayPushZeroFunction(ArrayType const& _type)
slot, offset := <indexAccess>(array, oldLen) slot, offset := <indexAccess>(array, oldLen)
})") })")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ResourceError))
("fetchLength", arrayLengthFunction(_type)) ("fetchLength", arrayLengthFunction(_type))
("indexAccess", storageArrayIndexAccessFunction(_type)) ("indexAccess", storageArrayIndexAccessFunction(_type))
("maxArrayLength", (u256(1) << 64).str()) ("maxArrayLength", (u256(1) << 64).str())
@ -1715,7 +1716,7 @@ string YulUtilFunctions::arrayAllocationSizeFunction(ArrayType const& _type)
} }
)"); )");
w("functionName", functionName); w("functionName", functionName);
w("panic", panicFunction()); w("panic", panicFunction(PanicCode::ResourceError));
w("byteArray", _type.isByteArray()); w("byteArray", _type.isByteArray());
w("dynamic", _type.isDynamicallySized()); w("dynamic", _type.isDynamicallySized());
return w.render(); return w.render();
@ -1786,7 +1787,7 @@ string YulUtilFunctions::storageArrayIndexAccessFunction(ArrayType const& _type)
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ArrayOutOfBounds))
("arrayLen", arrayLengthFunction(_type)) ("arrayLen", arrayLengthFunction(_type))
("dataAreaFunc", arrayDataAreaFunction(_type)) ("dataAreaFunc", arrayDataAreaFunction(_type))
("multipleItemsPerSlot", _type.baseType()->storageBytes() <= 16) ("multipleItemsPerSlot", _type.baseType()->storageBytes() <= 16)
@ -1816,7 +1817,7 @@ string YulUtilFunctions::memoryArrayIndexAccessFunction(ArrayType const& _type)
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ArrayOutOfBounds))
("arrayLen", arrayLengthFunction(_type)) ("arrayLen", arrayLengthFunction(_type))
("stride", to_string(_type.memoryStride())) ("stride", to_string(_type.memoryStride()))
("dynamicallySized", _type.isDynamicallySized()) ("dynamicallySized", _type.isDynamicallySized())
@ -1839,7 +1840,7 @@ string YulUtilFunctions::calldataArrayIndexAccessFunction(ArrayType const& _type
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ArrayOutOfBounds))
("stride", to_string(_type.calldataStride())) ("stride", to_string(_type.calldataStride()))
("dynamicallySized", _type.isDynamicallySized()) ("dynamicallySized", _type.isDynamicallySized())
("dynamicallyEncodedBase", _type.baseType()->isDynamicallyEncoded()) ("dynamicallyEncodedBase", _type.baseType()->isDynamicallyEncoded())
@ -2509,7 +2510,7 @@ string YulUtilFunctions::allocationFunction()
)") )")
("functionName", functionName) ("functionName", functionName)
("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer)) ("freeMemoryPointer", to_string(CompilerUtils::freeMemoryPointer))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::ResourceError))
.render(); .render();
}); });
} }
@ -3085,10 +3086,7 @@ string YulUtilFunctions::validatorFunction(Type const& _type, bool _revertOnFail
} }
)"); )");
templ("functionName", functionName); templ("functionName", functionName);
if (_revertOnFailure) PanicCode panicCode = PanicCode::Generic;
templ("failure", "revert(0, 0)");
else
templ("failure", panicFunction() + "()");
switch (_type.category()) switch (_type.category())
{ {
@ -3111,6 +3109,7 @@ string YulUtilFunctions::validatorFunction(Type const& _type, bool _revertOnFail
{ {
size_t members = dynamic_cast<EnumType const&>(_type).numberOfMembers(); size_t members = dynamic_cast<EnumType const&>(_type).numberOfMembers();
solAssert(members > 0, "empty enum should have caused a parser error."); solAssert(members > 0, "empty enum should have caused a parser error.");
panicCode = PanicCode::EnumConversionError;
templ("condition", "lt(value, " + to_string(members) + ")"); templ("condition", "lt(value, " + to_string(members) + ")");
break; break;
} }
@ -3121,6 +3120,11 @@ string YulUtilFunctions::validatorFunction(Type const& _type, bool _revertOnFail
solAssert(false, "Validation of type " + _type.identifier() + " requested."); solAssert(false, "Validation of type " + _type.identifier() + " requested.");
} }
if (_revertOnFailure)
templ("failure", "revert(0, 0)");
else
templ("failure", panicFunction(panicCode) + "()");
return templ.render(); return templ.render();
}); });
} }
@ -3196,7 +3200,7 @@ std::string YulUtilFunctions::decrementCheckedFunction(Type const& _type)
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
("minval", toCompactHexWithPrefix(type.min())) ("minval", toCompactHexWithPrefix(type.min()))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
.render(); .render();
@ -3237,7 +3241,7 @@ std::string YulUtilFunctions::incrementCheckedFunction(Type const& _type)
)") )")
("functionName", functionName) ("functionName", functionName)
("maxval", toCompactHexWithPrefix(type.max())) ("maxval", toCompactHexWithPrefix(type.max()))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
.render(); .render();
}); });
@ -3278,7 +3282,7 @@ string YulUtilFunctions::negateNumberCheckedFunction(Type const& _type)
("functionName", functionName) ("functionName", functionName)
("minval", toCompactHexWithPrefix(type.min())) ("minval", toCompactHexWithPrefix(type.min()))
("cleanupFunction", cleanupFunction(_type)) ("cleanupFunction", cleanupFunction(_type))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::UnderOverflow))
.render(); .render();
}); });
} }
@ -3400,7 +3404,7 @@ string YulUtilFunctions::storageSetToZeroFunction(Type const& _type)
)") )")
("functionName", functionName) ("functionName", functionName)
("clearArray", clearStorageArrayFunction(dynamic_cast<ArrayType const&>(_type))) ("clearArray", clearStorageArrayFunction(dynamic_cast<ArrayType const&>(_type)))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::Generic))
.render(); .render();
else if (_type.category() == Type::Category::Struct) else if (_type.category() == Type::Category::Struct)
return Whiskers(R"( return Whiskers(R"(
@ -3411,7 +3415,7 @@ string YulUtilFunctions::storageSetToZeroFunction(Type const& _type)
)") )")
("functionName", functionName) ("functionName", functionName)
("clearStruct", clearStorageStructFunction(dynamic_cast<StructType const&>(_type))) ("clearStruct", clearStorageStructFunction(dynamic_cast<StructType const&>(_type)))
("panic", panicFunction()) ("panic", panicFunction(PanicCode::Generic))
.render(); .render();
else else
solUnimplemented("setToZero for type " + _type.identifier() + " not yet implemented!"); solUnimplemented("setToZero for type " + _type.identifier() + " not yet implemented!");
@ -3645,16 +3649,20 @@ string YulUtilFunctions::revertReasonIfDebug(string const& _message)
return revertReasonIfDebug(m_revertStrings, _message); return revertReasonIfDebug(m_revertStrings, _message);
} }
string YulUtilFunctions::panicFunction() string YulUtilFunctions::panicFunction(util::PanicCode _code)
{ {
string functionName = "panic_error"; string functionName = "panic_error_" + toCompactHexWithPrefix(uint64_t(_code));
return m_functionCollector.createFunction(functionName, [&]() { return m_functionCollector.createFunction(functionName, [&]() {
return Whiskers(R"( return Whiskers(R"(
function <functionName>() { function <functionName>() {
invalid() mstore(0, <selector>)
mstore(4, <code>)
revert(0, 0x24)
} }
)") )")
("functionName", functionName) ("functionName", functionName)
("selector", util::selectorFromSignature("Panic(uint256)").str())
("code", toCompactHexWithPrefix(_code))
.render(); .render();
}); });
} }

View File

@ -28,6 +28,8 @@
#include <libsolidity/interface/DebugSettings.h> #include <libsolidity/interface/DebugSettings.h>
#include <libsolutil/ErrorCodes.h>
#include <memory> #include <memory>
#include <string> #include <string>
#include <vector> #include <vector>
@ -406,9 +408,8 @@ public:
std::string revertReasonIfDebug(std::string const& _message = ""); std::string revertReasonIfDebug(std::string const& _message = "");
/// Executes the invalid opcode. /// Reverts with ``Panic(uint256)`` and the given code.
/// Might use revert with special error code in the future. std::string panicFunction(util::PanicCode _code);
std::string panicFunction();
/// Returns the name of a function that decodes an error message. /// Returns the name of a function that decodes an error message.
/// signature: () -> arrayPtr /// signature: () -> arrayPtr

View File

@ -208,7 +208,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions()
} }
)"); )");
templ("functionName", funName); templ("functionName", funName);
templ("panic", m_utils.panicFunction()); templ("panic", m_utils.panicFunction(PanicCode::InvalidInternalFunction));
templ("in", suffixedVariableNameList("in_", 0, arity.in)); templ("in", suffixedVariableNameList("in_", 0, arity.in));
templ("out", suffixedVariableNameList("out_", 0, arity.out)); templ("out", suffixedVariableNameList("out_", 0, arity.out));

View File

@ -1302,7 +1302,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
define(modulus, *arguments[2]); define(modulus, *arguments[2]);
Whiskers templ("if iszero(<modulus>) { <panic>() }\n"); Whiskers templ("if iszero(<modulus>) { <panic>() }\n");
templ("modulus", modulus.name()); templ("modulus", modulus.name());
templ("panic", m_utils.panicFunction()); templ("panic", m_utils.panicFunction(PanicCode::DivisionByZero));
m_code << templ.render(); m_code << templ.render();
string args; string args;
@ -1367,7 +1367,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
t("allocateTemporaryMemory", m_utils.allocationTemporaryMemoryFunction()); t("allocateTemporaryMemory", m_utils.allocationTemporaryMemoryFunction());
t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction()); t("releaseTemporaryMemory", m_utils.releaseTemporaryMemoryFunction());
t("object", IRNames::creationObject(*contract)); t("object", IRNames::creationObject(*contract));
t("panic", m_utils.panicFunction()); t("panic", m_utils.panicFunction(PanicCode::ResourceError));
t("abiEncode", t("abiEncode",
m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false) m_context.abiFunctions().tupleEncoder(argumentTypes, functionType->parameterTypes(), false)
); );
@ -2023,7 +2023,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
)") )")
("index", index.name()) ("index", index.name())
("length", to_string(fixedBytesType.numBytes())) ("length", to_string(fixedBytesType.numBytes()))
("panic", m_utils.panicFunction()) ("panic", m_utils.panicFunction(PanicCode::ArrayOutOfBounds))
("array", IRVariable(_indexAccess.baseExpression()).name()) ("array", IRVariable(_indexAccess.baseExpression()).name())
("shl248", m_utils.shiftLeftFunction(256 - 8)) ("shl248", m_utils.shiftLeftFunction(256 - 8))
("result", IRVariable(_indexAccess).name()) ("result", IRVariable(_indexAccess).name())

View File

@ -9,6 +9,7 @@ set(sources
CommonIO.h CommonIO.h
Exceptions.cpp Exceptions.cpp
Exceptions.h Exceptions.h
ErrorCodes.h
FixedHash.h FixedHash.h
FunctionSelector.h FunctionSelector.h
IndentedWriter.cpp IndentedWriter.cpp

38
libsolutil/ErrorCodes.h Normal file
View File

@ -0,0 +1,38 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#pragma once
#include <string>
namespace solidity::util
{
enum class PanicCode
{
Generic = 0x00, // generic / unspecified error.
Assert = 0x01, // generic / unspecified error. Used by assert().
UnderOverflow = 0x11, // arithmetic underflow or overflow
DivisionByZero = 0x12, // division or modulo by zero
EnumConversionError = 0x21, // enum conversion error
EmptyArrayPop = 0x31, // empty array pop
ArrayOutOfBounds = 0x32, // array out of bounds access
ResourceError = 0x41, // resource error (too large allocation or too large array)
InvalidInternalFunction = 0x51, // calling invalid internal function
};
}

View File

@ -378,6 +378,7 @@ EVMDialectTyped::EVMDialectTyped(langutil::EVMVersion _evmVersion, bool _objectA
BuiltinContext&, BuiltinContext&,
std::function<void(Expression const&)> _visitExpression std::function<void(Expression const&)> _visitExpression
) { ) {
// TODO this should use a Panic.
// A value larger than 1 causes an invalid instruction. // A value larger than 1 causes an invalid instruction.
visitArguments(_assembly, _call, _visitExpression); visitArguments(_assembly, _call, _visitExpression);
_assembly.appendConstant(2); _assembly.appendConstant(2);

View File

@ -28,6 +28,7 @@
#include <test/evmc/evmc.hpp> #include <test/evmc/evmc.hpp>
#include <libsolutil/CommonIO.h> #include <libsolutil/CommonIO.h>
#include <libsolutil/FunctionSelector.h>
#include <liblangutil/Exceptions.h> #include <liblangutil/Exceptions.h>
@ -112,6 +113,14 @@ std::pair<bool, string> ExecutionFramework::compareAndCreateMessage(
return make_pair(false, message); return make_pair(false, message);
} }
bytes ExecutionFramework::panicData(util::PanicCode _code)
{
return
m_evmVersion.supportsReturndata() ?
toCompactBigEndian(selectorFromSignature32("Panic(uint256)"), 4) + encode(u256(_code)) :
bytes();
}
u256 ExecutionFramework::gasLimit() const u256 ExecutionFramework::gasLimit() const
{ {
return {m_evmcHost->tx_context.block_gas_limit}; return {m_evmcHost->tx_context.block_gas_limit};

View File

@ -33,6 +33,7 @@
#include <libsolutil/FixedHash.h> #include <libsolutil/FixedHash.h>
#include <libsolutil/Keccak256.h> #include <libsolutil/Keccak256.h>
#include <libsolutil/ErrorCodes.h>
#include <functional> #include <functional>
@ -200,6 +201,9 @@ public:
{ {
return bytes(); return bytes();
} }
/// @returns error returndata corresponding to the Panic(uint256) error code,
/// if REVERT is supported by the current EVM version and the empty string otherwise.
bytes panicData(util::PanicCode _code);
//@todo might be extended in the future //@todo might be extended in the future
template <class Arg> template <class Arg>

View File

@ -103,7 +103,7 @@ object "C_80" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -116,7 +116,7 @@ object "C_80" {
function checked_exp_t_rational_10_by_1_t_uint256(exponent) -> power { function checked_exp_t_rational_10_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent) exponent := cleanup_t_uint256(exponent)
if gt(exponent, 77) { panic_error() } if gt(exponent, 77) { panic_error_0x11() }
power := exp(10, exponent) power := exp(10, exponent)
} }
@ -124,7 +124,7 @@ object "C_80" {
function checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(exponent) -> power { function checked_exp_t_rational_115792089237316195423570985008687907853269984665640564039457584007913129639935_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent) exponent := cleanup_t_uint256(exponent)
if gt(exponent, 1) { panic_error() } if gt(exponent, 1) { panic_error_0x11() }
power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent) power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639935, exponent)
} }
@ -138,7 +138,7 @@ object "C_80" {
function checked_exp_t_rational_2_by_1_t_uint256(exponent) -> power { function checked_exp_t_rational_2_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent) exponent := cleanup_t_uint256(exponent)
if gt(exponent, 255) { panic_error() } if gt(exponent, 255) { panic_error_0x11() }
power := exp(2, exponent) power := exp(2, exponent)
} }
@ -152,7 +152,7 @@ object "C_80" {
function checked_exp_t_rational_minus_2_by_1_t_uint256(exponent) -> power { function checked_exp_t_rational_minus_2_by_1_t_uint256(exponent) -> power {
exponent := cleanup_t_uint256(exponent) exponent := cleanup_t_uint256(exponent)
if gt(exponent, 255) { panic_error() } if gt(exponent, 255) { panic_error_0x11() }
power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639934, exponent) power := exp(115792089237316195423570985008687907853269984665640564039457584007913129639934, exponent)
} }
@ -274,8 +274,16 @@ object "C_80" {
} }
function panic_error() { function panic_error_0x11() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x11)
revert(0, 0x24)
}
function panic_error_0x41() {
mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function shift_right_224_unsigned(value) -> newValue { function shift_right_224_unsigned(value) -> newValue {

View File

@ -57,7 +57,7 @@ object "D_15" {
if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) } if slt(add(calldatasize(), not(3)), _1) { revert(_1, _1) }
let _2 := datasize("C_2") let _2 := datasize("C_2")
let _3 := add(128, _2) let _3 := add(128, _2)
if or(gt(_3, 0xffffffffffffffff), lt(_3, 128)) { invalid() } if or(gt(_3, 0xffffffffffffffff), lt(_3, 128)) { panic_error_0x41() }
datacopy(128, dataoffset("C_2"), _2) datacopy(128, dataoffset("C_2"), _2)
pop(create(_1, 128, _2)) pop(create(_1, 128, _2))
return(allocateMemory(_1), _1) return(allocateMemory(_1), _1)
@ -69,9 +69,15 @@ object "D_15" {
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
function panic_error_0x41()
{
mstore(0, shl(224, 0x4e487b71))
mstore(4, 0x41)
revert(0, 0x24)
}
} }
object "C_2" { object "C_2" {
code { code {

View File

@ -33,7 +33,7 @@ object "C_59" {
if gt(offset, _3) { revert(_1, _1) } if gt(offset, _3) { revert(_1, _1) }
if iszero(slt(add(offset, 35), calldatasize())) { revert(_1, _1) } if iszero(slt(add(offset, 35), calldatasize())) { revert(_1, _1) }
let length := calldataload(add(4, offset)) let length := calldataload(add(4, offset))
if gt(length, _3) { invalid() } if gt(length, _3) { panic_error_0x41() }
let _4 := mul(length, _2) let _4 := mul(length, _2)
let dst := allocateMemory(add(_4, _2)) let dst := allocateMemory(add(_4, _2))
let dst_1 := dst let dst_1 := dst
@ -60,7 +60,7 @@ object "C_59" {
if slt(sub(end, headStart), 0x20) { revert(value, value) } if slt(sub(end, headStart), 0x20) { revert(value, value) }
let memPtr := mload(64) let memPtr := mload(64)
let newFreePtr := add(memPtr, 0x20) let newFreePtr := add(memPtr, 0x20)
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
value := memPtr value := memPtr
mstore(memPtr, calldataload(headStart)) mstore(memPtr, calldataload(headStart))
@ -87,14 +87,14 @@ object "C_59" {
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
function convert_t_stringliteral_6490_to_t_string() -> converted function convert_t_stringliteral_6490_to_t_string() -> converted
{ {
let memPtr := mload(64) let memPtr := mload(64)
let newFreePtr := add(memPtr, 160) let newFreePtr := add(memPtr, 160)
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
converted := memPtr converted := memPtr
mstore(memPtr, 100) mstore(memPtr, 100)
@ -109,26 +109,37 @@ object "C_59" {
} }
function fun_sumArray_58(vloc__s_22_mpos) -> vloc, vloc__27_mpos function fun_sumArray_58(vloc__s_22_mpos) -> vloc, vloc__27_mpos
{ {
let _1 := mload(vloc__s_22_mpos) if iszero(lt(vloc, mload(vloc__s_22_mpos))) { panic_error_0x32() }
if iszero(lt(vloc, _1)) { invalid() } let _1 := mload(mload(add(add(vloc__s_22_mpos, mul(vloc, 32)), 32)))
let _2 := mload(mload(add(add(vloc__s_22_mpos, mul(vloc, 32)), 32))) let _2, _3 := storage_array_index_access$_t_struct$_S_storage(vloc, vloc)
let _3, _4 := storage_array_index_access$_t_struct$_S_storage(vloc, vloc) sstore(_2, _1)
sstore(_3, _2) if iszero(lt(0x01, mload(vloc__s_22_mpos))) { panic_error_0x32() }
if iszero(lt(0x01, _1)) { invalid() } let _4 := mload(mload(add(vloc__s_22_mpos, 64)))
let _5 := mload(mload(add(vloc__s_22_mpos, 64))) if iszero(lt(vloc, 0x02)) { panic_error_0x32() }
if iszero(lt(vloc, 0x02)) { invalid() }
let slot := add(0x02, vloc) let slot := add(0x02, vloc)
let _6 := sload(slot) let _5 := sload(slot)
let shiftBits := mul(vloc, 8) let shiftBits := mul(vloc, 8)
let mask := shl(shiftBits, not(0)) let mask := shl(shiftBits, not(0))
sstore(slot, or(and(_6, not(mask)), and(shl(shiftBits, _5), mask))) sstore(slot, or(and(_5, not(mask)), and(shl(shiftBits, _4), mask)))
let _7, _8 := storage_array_index_access$_t_struct$_S_storage(0x02, vloc) let _6, _7 := storage_array_index_access$_t_struct$_S_storage(0x02, vloc)
vloc := extract_from_storage_value_dynamict_uint256(sload(_7), _8) vloc := extract_from_storage_value_dynamict_uint256(sload(_6), _7)
vloc__27_mpos := convert_t_stringliteral_6490_to_t_string() vloc__27_mpos := convert_t_stringliteral_6490_to_t_string()
} }
function panic_error_0x32()
{
mstore(0, shl(224, 0x4e487b71))
mstore(4, 0x32)
revert(0, 0x24)
}
function panic_error_0x41()
{
mstore(0, shl(224, 0x4e487b71))
mstore(4, 0x41)
revert(0, 0x24)
}
function storage_array_index_access$_t_struct$_S_storage(array, index) -> slot, offset function storage_array_index_access$_t_struct$_S_storage(array, index) -> slot, offset
{ {
if iszero(lt(index, 0x02)) { invalid() } if iszero(lt(index, 0x02)) { panic_error_0x32() }
slot := add(array, index) slot := add(array, index)
offset := offset offset := offset
} }

View File

@ -33,14 +33,12 @@ object "Arraysum_33" {
for { } for { }
lt(vloc_i, _2) lt(vloc_i, _2)
{ {
if eq(vloc_i, not(0)) { invalid() } if eq(vloc_i, not(0)) { panic_error_0x11() }
vloc_i := add(vloc_i, 1) vloc_i := add(vloc_i, 1)
} }
{ {
mstore(_1, _1) mstore(_1, _1)
let _3 := sload(add(keccak256(_1, 0x20), vloc_i)) vloc_sum := checked_add_t_uint256(vloc_sum, sload(add(keccak256(_1, 0x20), vloc_i)))
if gt(vloc_sum, not(_3)) { invalid() }
vloc_sum := add(vloc_sum, _3)
} }
let memPos := allocateMemory(_1) let memPos := allocateMemory(_1)
return(memPos, sub(abi_encode_uint(memPos, vloc_sum), memPos)) return(memPos, sub(abi_encode_uint(memPos, vloc_sum), memPos))
@ -57,9 +55,25 @@ object "Arraysum_33" {
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { invalid() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr))
{
mstore(0, shl(224, 0x4e487b71))
mstore(4, 0x41)
revert(0, 0x24)
}
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
function checked_add_t_uint256(x, y) -> sum
{
if gt(x, not(y)) { panic_error_0x11() }
sum := add(x, y)
}
function panic_error_0x11()
{
mstore(0, shl(224, 0x4e487b71))
mstore(4, 0x11)
revert(0, 0x24)
}
} }
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -44,13 +44,17 @@ object \"C_6\" {
{ {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
function fun_f_5() function fun_f_5()
{ } { }
function panic_error() function panic_error_0x41()
{ invalid() } {
mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
}
function shift_right_224_unsigned(value) -> newValue function shift_right_224_unsigned(value) -> newValue
{ newValue := shr(224, value) } { newValue := shr(224, value) }
} }

View File

@ -61,7 +61,7 @@ object \"C_6\" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -69,8 +69,10 @@ object \"C_6\" {
} }
function panic_error() { function panic_error_0x41() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function shift_right_224_unsigned(value) -> newValue { function shift_right_224_unsigned(value) -> newValue {

File diff suppressed because one or more lines are too long

View File

@ -71,7 +71,7 @@ object \"C_10\" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -116,8 +116,10 @@ object \"C_10\" {
} }
function panic_error() { function panic_error_0x41() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function round_up_to_mul_of_32(value) -> result { function round_up_to_mul_of_32(value) -> result {

View File

@ -67,7 +67,7 @@ object \"C_10\" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -88,8 +88,10 @@ object \"C_10\" {
} }
function panic_error() { function panic_error_0x41() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function shift_right_224_unsigned(value) -> newValue { function shift_right_224_unsigned(value) -> newValue {

View File

@ -67,7 +67,7 @@ object \"C_10\" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -93,8 +93,10 @@ object \"C_10\" {
} }
function panic_error() { function panic_error_0x41() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function shift_left_224(value) -> newValue { function shift_left_224(value) -> newValue {

View File

@ -71,7 +71,7 @@ object \"C_10\" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -120,8 +120,10 @@ object \"C_10\" {
} }
function panic_error() { function panic_error_0x41() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function round_up_to_mul_of_32(value) -> result { function round_up_to_mul_of_32(value) -> result {

View File

@ -67,7 +67,7 @@ object \"C_10\" {
memPtr := mload(64) memPtr := mload(64)
let newFreePtr := add(memPtr, size) let newFreePtr := add(memPtr, size)
// protect against overflow // protect against overflow
if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error() } if or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { panic_error_0x41() }
mstore(64, newFreePtr) mstore(64, newFreePtr)
} }
@ -93,8 +93,10 @@ object \"C_10\" {
} }
function panic_error() { function panic_error_0x41() {
invalid() mstore(0, 35408467139433450592217433187231851964531694900788300625387963629091585785856)
mstore(4, 0x41)
revert(0, 0x24)
} }
function shift_left_224(value) -> newValue { function shift_left_224(value) -> newValue {

View File

@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(enum_type_cleanup)
compileAndRun(sourceCode); compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f(uint256)", 0) == encodeArgs(0)); BOOST_CHECK(callContractFunction("f(uint256)", 0) == encodeArgs(0));
BOOST_CHECK(callContractFunction("f(uint256)", 1) == encodeArgs(1)); BOOST_CHECK(callContractFunction("f(uint256)", 1) == encodeArgs(1));
BOOST_CHECK(callContractFunction("f(uint256)", 2) == encodeArgs()); BOOST_CHECK(callContractFunction("f(uint256)", 2) == panicData(PanicCode::EnumConversionError));
) )
} }

View File

@ -201,8 +201,12 @@ TestCase::TestResult SemanticTest::runTest(ostream& _stream, string const& _line
); );
} }
if ((m_transactionSuccessful == test.call().expectations.failure) bool outputMismatch = (output != test.call().expectations.rawBytes());
|| (output != test.call().expectations.rawBytes())) // Pre byzantium, it was not possible to return failure data, so we disregard
// output mismatch for those EVM versions.
if (test.call().expectations.failure && !m_transactionSuccessful && !m_evmVersion.supportsReturndata())
outputMismatch = false;
if (m_transactionSuccessful != !test.call().expectations.failure || outputMismatch)
success = false; success = false;
test.setFailure(!m_transactionSuccessful); test.setFailure(!m_transactionSuccessful);

View File

@ -33,6 +33,7 @@
#include <libevmasm/Assembly.h> #include <libevmasm/Assembly.h>
#include <libsolutil/Keccak256.h> #include <libsolutil/Keccak256.h>
#include <libsolutil/ErrorCodes.h>
#include <boost/range/adaptor/transformed.hpp> #include <boost/range/adaptor/transformed.hpp>
#include <boost/test/unit_test.hpp> #include <boost/test/unit_test.hpp>
@ -2554,7 +2555,7 @@ BOOST_AUTO_TEST_CASE(generic_staticcall)
ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23 + 42)); ABI_CHECK(callContractFunction("g(address)", c_addressA), encodeArgs(true, 0x40, 0x20, 23 + 42));
ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false, 0x40, 0x00)); ABI_CHECK(callContractFunction("h(address)", c_addressA), encodeArgs(false, 0x40, 0x00));
ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true, 0x40, 0x20, 42)); ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 42), encodeArgs(true, 0x40, 0x20, 42));
ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false, 0x40, 0x00)); ABI_CHECK(callContractFunction("i(address,uint256)", c_addressA, 23), encodeArgs(false, 0x40, 0x24) + panicData(PanicCode::Assert) + bytes(32 - 4, 0));
} }
} }
@ -3678,8 +3679,7 @@ BOOST_AUTO_TEST_CASE(invalid_enum_logged)
BOOST_REQUIRE_EQUAL(logTopic(0, 0), util::keccak256(string("Log(uint8)"))); BOOST_REQUIRE_EQUAL(logTopic(0, 0), util::keccak256(string("Log(uint8)")));
BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(0))); BOOST_CHECK_EQUAL(h256(logData(0)), h256(u256(0)));
// should throw ABI_CHECK(callContractFunction("test_log()"), panicData(PanicCode::EnumConversionError));
ABI_CHECK(callContractFunction("test_log()"), encodeArgs());
} }
BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund) BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
@ -3696,7 +3696,7 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
} }
} }
)"; )";
ABI_CHECK(compileAndRunWithoutCheck({{"", sourceCode}}, 0, "A"), encodeArgs()); ABI_CHECK(compileAndRunWithoutCheck({{"", sourceCode}}, 0, "A"), panicData(PanicCode::ArrayOutOfBounds));
BOOST_CHECK(!m_transactionSuccessful); BOOST_CHECK(!m_transactionSuccessful);
} }
@ -4176,7 +4176,7 @@ BOOST_AUTO_TEST_CASE(calldata_bytes_array_bounds)
); );
ABI_CHECK( ABI_CHECK(
callContractFunction("f(bytes[],uint256)", 0x40, 2, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)), callContractFunction("f(bytes[],uint256)", 0x40, 2, 1, 0x20, 2, bytes{'a', 'b'} + bytes(30, 0)),
encodeArgs() panicData(PanicCode::ArrayOutOfBounds)
); );
} }
@ -4226,11 +4226,9 @@ BOOST_AUTO_TEST_CASE(calldata_array_two_dimensional)
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j]));
ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j])); ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256)", 0x60, i, j, encoding), encodeArgs(data[i][j]));
} }
// out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs());
} }
// out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), encodeArgs());
} }
} }
@ -4308,14 +4306,11 @@ BOOST_AUTO_TEST_CASE(calldata_array_dynamic_three_dimensional)
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k]));
ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k])); ABI_CHECK(callContractFunction("reenc(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, k, encoding), encodeArgs(data[i][j][k]));
} }
// out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, data[i][j].size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256,uint256)", 0x80, i, j, data[i][j].size(), encoding), encodeArgs());
} }
// out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256,uint256)", 0x60, i, data[i].size(), encoding), encodeArgs());
} }
// out of bounds access ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), panicData(PanicCode::ArrayOutOfBounds));
ABI_CHECK(callContractFunction("test(" + arrayType + ",uint256)", 0x40, data.size(), encoding), encodeArgs());
} }
} }

View File

@ -327,9 +327,23 @@ BOOST_AUTO_TEST_CASE(arithmetic)
)"; )";
bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}}); bytes code = compileFirstExpression(sourceCode, {}, {{"test", "f", "y"}});
bytes panic =
bytes{uint8_t(Instruction::PUSH32)} +
fromHex("4E487B7100000000000000000000000000000000000000000000000000000000") +
bytes{
uint8_t(Instruction::PUSH1), 0x0,
uint8_t(Instruction::MSTORE),
uint8_t(Instruction::PUSH1), 0x12,
uint8_t(Instruction::PUSH1), 0x4,
uint8_t(Instruction::MSTORE),
uint8_t(Instruction::PUSH1), 0x24,
uint8_t(Instruction::PUSH1), 0x0,
uint8_t(Instruction::REVERT)
};
bytes expectation; bytes expectation;
if (solidity::test::CommonOptions::get().optimize) if (solidity::test::CommonOptions::get().optimize)
expectation = { expectation = bytes{
uint8_t(Instruction::PUSH1), 0x2, uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x3, uint8_t(Instruction::PUSH1), 0x3,
uint8_t(Instruction::PUSH1), 0x5, uint8_t(Instruction::PUSH1), 0x5,
@ -346,24 +360,24 @@ BOOST_AUTO_TEST_CASE(arithmetic)
uint8_t(Instruction::DUP2), uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1b, uint8_t(Instruction::PUSH1), 0x48,
uint8_t(Instruction::JUMPI), uint8_t(Instruction::JUMPI)
uint8_t(Instruction::INVALID), } + panic + bytes{
uint8_t(Instruction::JUMPDEST), uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::MOD), uint8_t(Instruction::MOD),
uint8_t(Instruction::DUP2), uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x24, uint8_t(Instruction::PUSH1), 0x7e,
uint8_t(Instruction::JUMPI), uint8_t(Instruction::JUMPI)
uint8_t(Instruction::INVALID), } + panic + bytes{
uint8_t(Instruction::JUMPDEST), uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::DIV), uint8_t(Instruction::DIV),
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::MUL) uint8_t(Instruction::MUL)
}; };
else else
expectation = { expectation = bytes{
uint8_t(Instruction::PUSH1), 0x1, uint8_t(Instruction::PUSH1), 0x1,
uint8_t(Instruction::PUSH1), 0x2, uint8_t(Instruction::PUSH1), 0x2,
uint8_t(Instruction::PUSH1), 0x3, uint8_t(Instruction::PUSH1), 0x3,
@ -381,21 +395,22 @@ BOOST_AUTO_TEST_CASE(arithmetic)
uint8_t(Instruction::DUP2), uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x1d, uint8_t(Instruction::PUSH1), 0x4a,
uint8_t(Instruction::JUMPI), uint8_t(Instruction::JUMPI)
uint8_t(Instruction::INVALID), } + panic + bytes{
uint8_t(Instruction::JUMPDEST), uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::MOD), uint8_t(Instruction::MOD),
uint8_t(Instruction::DUP2), uint8_t(Instruction::DUP2),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::ISZERO), uint8_t(Instruction::ISZERO),
uint8_t(Instruction::PUSH1), 0x26, uint8_t(Instruction::PUSH1), 0x80,
uint8_t(Instruction::JUMPI), uint8_t(Instruction::JUMPI)
uint8_t(Instruction::INVALID), } + panic + bytes{
uint8_t(Instruction::JUMPDEST), uint8_t(Instruction::JUMPDEST),
uint8_t(Instruction::DIV), uint8_t(Instruction::DIV),
uint8_t(Instruction::MUL) uint8_t(Instruction::MUL)
}; };
BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end()); BOOST_CHECK_EQUAL_COLLECTIONS(code.begin(), code.end(), expectation.begin(), expectation.end());
} }

View File

@ -14,9 +14,9 @@ contract C {
} }
// ---- // ----
// creation: // creation:
// codeDepositCost: 1107400 // codeDepositCost: 1116400
// executionCost: 1154 // executionCost: 1160
// totalCost: 1108554 // totalCost: 1117560
// external: // external:
// a(): 1130 // a(): 1130
// b(uint256): infinite // b(uint256): infinite

View File

@ -17,9 +17,9 @@ contract C {
// optimize-yul: true // optimize-yul: true
// ---- // ----
// creation: // creation:
// codeDepositCost: 605000 // codeDepositCost: 615400
// executionCost: 638 // executionCost: 651
// totalCost: 605638 // totalCost: 616051
// external: // external:
// a(): 1029 // a(): 1029
// b(uint256): 2084 // b(uint256): 2084

View File

@ -24,9 +24,9 @@ contract Large {
} }
// ---- // ----
// creation: // creation:
// codeDepositCost: 637600 // codeDepositCost: 961600
// executionCost: 670 // executionCost: 1001
// totalCost: 638270 // totalCost: 962601
// external: // external:
// a(): 1051 // a(): 1051
// b(uint256): 2046 // b(uint256): 2046

View File

@ -27,9 +27,9 @@ contract Large {
// optimize-runs: 2 // optimize-runs: 2
// ---- // ----
// creation: // creation:
// codeDepositCost: 261200 // codeDepositCost: 301200
// executionCost: 300 // executionCost: 343
// totalCost: 261500 // totalCost: 301543
// external: // external:
// a(): 998 // a(): 998
// b(uint256): 2305 // b(uint256): 2305

View File

@ -11,9 +11,9 @@ contract Medium {
} }
// ---- // ----
// creation: // creation:
// codeDepositCost: 253800 // codeDepositCost: 361800
// executionCost: 294 // executionCost: 399
// totalCost: 254094 // totalCost: 362199
// external: // external:
// a(): 1028 // a(): 1028
// b(uint256): 2046 // b(uint256): 2046

View File

@ -14,9 +14,9 @@ contract Medium {
// optimize-runs: 2 // optimize-runs: 2
// ---- // ----
// creation: // creation:
// codeDepositCost: 141600 // codeDepositCost: 169600
// executionCost: 190 // executionCost: 214
// totalCost: 141790 // totalCost: 169814
// external: // external:
// a(): 998 // a(): 998
// b(uint256): 2063 // b(uint256): 2063

View File

@ -6,9 +6,9 @@ contract Small {
} }
// ---- // ----
// creation: // creation:
// codeDepositCost: 85400 // codeDepositCost: 103400
// executionCost: 135 // executionCost: 153
// totalCost: 85535 // totalCost: 103553
// external: // external:
// fallback: 129 // fallback: 129
// a(): 983 // a(): 983

View File

@ -9,9 +9,9 @@ contract Small {
// optimize-runs: 2 // optimize-runs: 2
// ---- // ----
// creation: // creation:
// codeDepositCost: 61200 // codeDepositCost: 72800
// executionCost: 111 // executionCost: 123
// totalCost: 61311 // totalCost: 72923
// external: // external:
// fallback: 118 // fallback: 118
// a(): 976 // a(): 976

View File

@ -21,6 +21,6 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// f(uint256): 0 -> FAILURE // f(uint256): 0 -> FAILURE, hex"4e487b71", 0x12
// g(uint256): 0 -> FAILURE // g(uint256): 0 -> FAILURE, hex"4e487b71", 0x12
// h() -> 2 // h() -> 2

View File

@ -14,5 +14,5 @@ contract D {
} }
} }
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x11
// g(), 100 wei -> 1 // g(), 100 wei -> 1

View File

@ -10,4 +10,4 @@ contract C {
// f(uint16,uint16): 65534, 0 -> 0xfffe // f(uint16,uint16): 65534, 0 -> 0xfffe
// f(uint16,uint16): 65536, 0 -> 0x00 // f(uint16,uint16): 65536, 0 -> 0x00
// f(uint16,uint16): 65535, 0 -> 0xffff // f(uint16,uint16): 65535, 0 -> 0xffff
// f(uint16,uint16): 65535, 1 -> FAILURE // f(uint16,uint16): 65535, 1 -> FAILURE, hex"4e487b71", 0x11

View File

@ -10,5 +10,5 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// f(uint16,uint16,uint16): 0xe000, 0xe500, 2 -> FAILURE // f(uint16,uint16,uint16): 0xe000, 0xe500, 2 -> FAILURE, hex"4e487b71", 0x11
// f(uint16,uint16,uint16): 0xe000, 0x1000, 0x1000 -> 0x00 // f(uint16,uint16,uint16): 0xe000, 0x1000, 0x1000 -> 0x00

View File

@ -12,4 +12,4 @@ contract C {
// compileViaYul: also // compileViaYul: also
// ---- // ----
// f(uint16,uint16,uint16): 0xe000, 0xe500, 2 -> 58626 // f(uint16,uint16,uint16): 0xe000, 0xe500, 2 -> 58626
// f(uint16,uint16,uint16): 0x1000, 0xe500, 0xe000 -> FAILURE // f(uint16,uint16,uint16): 0x1000, 0xe500, 0xe000 -> FAILURE, hex"4e487b71", 0x11

View File

@ -11,6 +11,6 @@ contract C {
// compileViaYul: also // compileViaYul: also
// ---- // ----
// div(uint256,uint256): 7, 2 -> 3 // div(uint256,uint256): 7, 2 -> 3
// div(uint256,uint256): 7, 0 -> FAILURE # throws # // div(uint256,uint256): 7, 0 -> FAILURE, hex"4e487b71", 0x12 # throws #
// mod(uint256,uint256): 7, 2 -> 1 // mod(uint256,uint256): 7, 2 -> 1
// mod(uint256,uint256): 7, 0 -> FAILURE # throws # // mod(uint256,uint256): 7, 0 -> FAILURE, hex"4e487b71", 0x12 # throws #

View File

@ -20,5 +20,5 @@ contract C {
// f(int256,int256): -7, 5 -> -2 // f(int256,int256): -7, 5 -> -2
// f(int256,int256): -7, 5 -> -2 // f(int256,int256): -7, 5 -> -2
// f(int256,int256): -5, -5 -> 0 // f(int256,int256): -5, -5 -> 0
// g(bool): true -> FAILURE // g(bool): true -> FAILURE, hex"4e487b71", 0x11
// g(bool): false -> -57896044618658097711785492504343953926634992332820282019728792003956564819968 // g(bool): false -> -57896044618658097711785492504343953926634992332820282019728792003956564819968

View File

@ -14,4 +14,4 @@ contract C {
// ---- // ----
// f(uint16): 7 -> 0x0207 // f(uint16): 7 -> 0x0207
// f(uint16): 0xffff -> 511 // f(uint16): 0xffff -> 511
// f(uint16): 0xfeff -> FAILURE // f(uint16): 0xfeff -> FAILURE, hex"4e487b71", 0x11

View File

@ -17,6 +17,6 @@ contract C {
// compileViaYul: also // compileViaYul: also
// ---- // ----
// div(uint256,uint256): 7, 2 -> 3 // div(uint256,uint256): 7, 2 -> 3
// div(uint256,uint256): 7, 0 -> FAILURE # throws # // div(uint256,uint256): 7, 0 -> FAILURE, hex"4e487b71", 0x12 # throws #
// mod(uint256,uint256): 7, 2 -> 1 // mod(uint256,uint256): 7, 2 -> 1
// mod(uint256,uint256): 7, 0 -> FAILURE # throws # // mod(uint256,uint256): 7, 0 -> FAILURE, hex"4e487b71", 0x12 # throws #

View File

@ -9,4 +9,4 @@ contract c {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// test() -> FAILURE // test() -> FAILURE, hex"4e487b71", 0x31

View File

@ -12,4 +12,4 @@ contract c {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// test() -> FAILURE // test() -> FAILURE, hex"4e487b71", 0x31

View File

@ -24,23 +24,23 @@ contract C {
// f(uint256[],uint256,uint256): 0x80, -1, 0, 0, 1, 42 -> FAILURE // f(uint256[],uint256,uint256): 0x80, -1, 0, 0, 1, 42 -> FAILURE
// f(uint256[],uint256,uint256): 0x80, -1, -1, 0, 1, 42 -> FAILURE // f(uint256[],uint256,uint256): 0x80, -1, -1, 0, 1, 42 -> FAILURE
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 0, 1, 42 -> 42, 42, 42 // g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 0, 1, 42 -> 42, 42, 42
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 1, 1, 42 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 1, 1, 42 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 0, 0, 1, 42 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 0, 0, 0, 1, 42 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 1, 1, 0, 1, 42 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 1, 1, 0, 1, 42 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4201, 0x4201, 0x4201 // g(uint256[],uint256,uint256,uint256): 0x80, 0, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4201, 0x4201, 0x4201
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 5, 4, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205 // g(uint256[],uint256,uint256,uint256): 0x80, 0, 5, 4, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 5, 5, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 0, 5, 5, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 1, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4202, 0x4202, 0x4202 // g(uint256[],uint256,uint256,uint256): 0x80, 1, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4202, 0x4202, 0x4202
// g(uint256[],uint256,uint256,uint256): 0x80, 1, 5, 3, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205 // g(uint256[],uint256,uint256,uint256): 0x80, 1, 5, 3, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205
// g(uint256[],uint256,uint256,uint256): 0x80, 1, 5, 4, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 1, 5, 4, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205 // g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205
// g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 5, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 5, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4201, 0x4201, 0x4201 // g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4201, 0x4201, 0x4201
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4201, 0x4201, 0x4201 // g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4201, 0x4201, 0x4201
// g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 0, 1, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 1, 2, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4202, 0x4202, 0x4202 // g(uint256[],uint256,uint256,uint256): 0x80, 1, 2, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4202, 0x4202, 0x4202
// g(uint256[],uint256,uint256,uint256): 0x80, 1, 2, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 1, 2, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32
// g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205 // g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 0, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> 0x4205, 0x4205, 0x4205
// g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE // g(uint256[],uint256,uint256,uint256): 0x80, 4, 5, 1, 5, 0x4201, 0x4202, 0x4203, 0x4204, 0x4205 -> FAILURE, hex"4e487b71", 0x32

View File

@ -19,4 +19,4 @@ contract C {
// ---- // ----
// one() -> 3 // one() -> 3
// two() -> FAILURE // two() -> FAILURE, hex"4e487b71", 0x51

View File

@ -22,5 +22,5 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x41
// g() -> FAILURE // g() -> FAILURE, hex"4e487b71", 0x41

View File

@ -24,11 +24,11 @@ contract c {
// compileViaYul: also // compileViaYul: also
// ---- // ----
// length() -> 0 // length() -> 0
// get(uint256): 3 -> FAILURE // get(uint256): 3 -> FAILURE, hex"4e487b71", 0x32
// enlarge(uint256): 4 -> 4 // enlarge(uint256): 4 -> 4
// length() -> 4 // length() -> 4
// set(uint256,uint256): 3, 4 -> true // set(uint256,uint256): 3, 4 -> true
// get(uint256): 3 -> 4 // get(uint256): 3 -> 4
// length() -> 4 // length() -> 4
// set(uint256,uint256): 4, 8 -> FAILURE // set(uint256,uint256): 4, 8 -> FAILURE, hex"4e487b71", 0x32
// length() -> 4 // length() -> 4

View File

@ -16,5 +16,5 @@ contract A {
// compileViaYul: also // compileViaYul: also
// ---- // ----
// test() -> false // test() -> false
// testIt() -> FAILURE // testIt() -> FAILURE, hex"4e487b71", 0x32
// test() -> false // test() -> false

View File

@ -20,9 +20,9 @@ contract c {
// ---- // ----
// length() -> 4 // length() -> 4
// set(uint256,uint256): 3, 4 -> true // set(uint256,uint256): 3, 4 -> true
// set(uint256,uint256): 4, 5 -> FAILURE // set(uint256,uint256): 4, 5 -> FAILURE, hex"4e487b71", 0x32
// set(uint256,uint256): 400, 5 -> FAILURE // set(uint256,uint256): 400, 5 -> FAILURE, hex"4e487b71", 0x32
// get(uint256): 3 -> 4 // get(uint256): 3 -> 4
// get(uint256): 4 -> FAILURE // get(uint256): 4 -> FAILURE, hex"4e487b71", 0x32
// get(uint256): 400 -> FAILURE // get(uint256): 400 -> FAILURE, hex"4e487b71", 0x32
// length() -> 4 // length() -> 4

View File

@ -38,4 +38,4 @@ contract C {
// test(uint256,uint256): 10, 2 -> 13 // test(uint256,uint256): 10, 2 -> 13
// test(uint256,uint256): 10, 3 -> 15 // test(uint256,uint256): 10, 3 -> 15
// test(uint256,uint256): 10, 4 -> 18 // test(uint256,uint256): 10, 4 -> 18
// test(uint256,uint256): 10, 5 -> FAILURE // test(uint256,uint256): 10, 5 -> FAILURE, hex"4e487b71", 0x51

View File

@ -23,9 +23,10 @@ contract test {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// EVMVersion: >=byzantium
// ---- // ----
// getChoiceExp(uint256): 3 -> FAILURE # These should throw # // getChoiceExp(uint256): 3 -> FAILURE, hex"4e487b71", 33 # These should throw #
// getChoiceFromSigned(int256): -1 -> FAILURE // getChoiceFromSigned(int256): -1 -> FAILURE, hex"4e487b71", 33
// getChoiceFromNegativeLiteral() -> FAILURE // getChoiceFromNegativeLiteral() -> FAILURE, hex"4e487b71", 33
// getChoiceExp(uint256): 2 -> 2 # These should work # // getChoiceExp(uint256): 2 -> 2 # These should work #
// getChoiceExp(uint256): 0 -> 0 // getChoiceExp(uint256): 0 -> 0

View File

@ -0,0 +1,32 @@
contract test {
enum ActionChoices {GoLeft, GoRight, GoStraight}
constructor() {}
function getChoiceExp(uint256 x) public returns (uint256 d) {
choice = ActionChoices(x);
d = uint256(choice);
}
function getChoiceFromSigned(int256 x) public returns (uint256 d) {
choice = ActionChoices(x);
d = uint256(choice);
}
function getChoiceFromNegativeLiteral() public returns (uint256 d) {
choice = ActionChoices(-1);
d = uint256(choice);
}
ActionChoices choice;
}
// ====
// EVMVersion: <byzantium
// compileViaYul: also
// ----
// getChoiceExp(uint256): 3 -> FAILURE # These should throw #
// getChoiceFromSigned(int256): -1 -> FAILURE
// getChoiceFromNegativeLiteral() -> FAILURE
// getChoiceExp(uint256): 2 -> 2 # These should work #
// getChoiceExp(uint256): 0 -> 0

View File

@ -14,5 +14,5 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// intern() -> FAILURE # This should throw exceptions # // intern() -> FAILURE, hex"4e487b71", 0x51 # This should throw exceptions #
// extern() -> FAILURE // extern() -> FAILURE

View File

@ -17,4 +17,4 @@ contract C {
} }
// ---- // ----
// t() -> FAILURE // t() -> FAILURE, hex"4e487b71", 0x51

View File

@ -18,4 +18,4 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// t() -> FAILURE // t() -> FAILURE, hex"4e487b71", 0x51

View File

@ -22,17 +22,17 @@ contract C {
} }
} }
// ==== // ====
// compileViaYul: also
// EVMVersion: >=byzantium // EVMVersion: >=byzantium
// compileViaYul: also
// ---- // ----
// get() -> 0x00 // get() -> 0x00
// assert0_delegated() -> 0x01, 0x40, 0x0 // assert0_delegated() -> 0x01, 0x40, 0x0
// get_delegated() -> 0x01, 0x40, 0x20, 0x0 // get_delegated() -> 0x01, 0x40, 0x20, 0x0
// set(uint256): 0x01 -> // set(uint256): 0x01 ->
// get() -> 0x01 // get() -> 0x01
// assert0_delegated() -> 0x00, 0x40, 0x0 // assert0_delegated() -> 0x00, 0x40, 0x24, 0x4e487b7100000000000000000000000000000000000000000000000000000000, 0x0100000000000000000000000000000000000000000000000000000000
// get_delegated() -> 0x01, 0x40, 0x20, 0x1 // get_delegated() -> 0x01, 0x40, 0x20, 0x1
// set(uint256): 0x2a -> // set(uint256): 0x2a ->
// get() -> 0x2a // get() -> 0x2a
// assert0_delegated() -> 0x00, 0x40, 0x0 // assert0_delegated() -> 0x00, 0x40, 0x24, 0x4e487b7100000000000000000000000000000000000000000000000000000000, 0x0100000000000000000000000000000000000000000000000000000000
// get_delegated() -> 0x01, 0x40, 0x20, 0x2a // get_delegated() -> 0x01, 0x40, 0x20, 0x2a

View File

@ -8,4 +8,4 @@ contract test {
// ---- // ----
// f() -> // f() ->
// g() -> FAILURE // g() -> FAILURE
// h() -> FAILURE // h() -> FAILURE, hex"4e487b71", 0x01

View File

@ -13,4 +13,4 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// test() -> FAILURE // test() -> FAILURE, hex"4e487b71", 0x51

View File

@ -24,4 +24,4 @@ contract C {
// set() -> 7 // set() -> 7
// ca() -> 7 // ca() -> 7
// d() -> 1 // d() -> 1
// ca() -> FAILURE // ca() -> FAILURE, hex"4e487b71", 0x51

View File

@ -8,4 +8,4 @@ contract Test {
} }
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x51

View File

@ -16,6 +16,6 @@ contract C {
// ---- // ----
// g() -> 2 // g() -> 2
// h() -> FAILURE // h() -> FAILURE, hex"4e487b71", 0x51
// set() -> // set() ->
// h() -> 2 // h() -> 2

View File

@ -51,6 +51,6 @@ contract C {
// j(uint256): 1 -> 1 // j(uint256): 1 -> 1
// j(uint256): 2 -> 4 // j(uint256): 2 -> 4
// j(uint256): 4 -> 16 // j(uint256): 4 -> 16
// k(uint256): 1 -> FAILURE // k(uint256): 1 -> FAILURE, hex"4e487b71", 0x01
// k(uint256): 2 -> FAILURE // k(uint256): 2 -> FAILURE, hex"4e487b71", 0x01
// k(uint256): 4 -> FAILURE // k(uint256): 4 -> FAILURE, hex"4e487b71", 0x01

View File

@ -17,8 +17,8 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x01
// g(bool): false -> FAILURE // g(bool): false -> FAILURE, hex"4e487b71", 0x01
// g(bool): true -> true // g(bool): true -> true
// h(bool): false -> FAILURE // h(bool): false -> FAILURE
// h(bool): true -> true // h(bool): true -> true

View File

@ -16,6 +16,7 @@ contract C {
} }
} }
// ==== // ====
// EVMVersion: >=byzantium
// compileViaYul: also // compileViaYul: also
// ---- // ----
// test() -> FAILURE # should throw # // test() -> FAILURE, hex"4e487b71", 33 # should throw #

View File

@ -26,7 +26,8 @@ contract C {
// ==== // ====
// compileViaYul: also // compileViaYul: also
// EVMVersion: >=byzantium
// ---- // ----
// test_return() -> FAILURE # both should throw # // test_return() -> FAILURE, hex"4e487b71", 33 # both should throw #
// test_inline_assignment() -> FAILURE // test_inline_assignment() -> FAILURE, hex"4e487b71", 33
// test_assignment() -> FAILURE // test_assignment() -> FAILURE, hex"4e487b71", 33

View File

@ -24,7 +24,8 @@ contract C {
} }
// ==== // ====
// compileViaYul: also // compileViaYul: also
// EVMVersion: >=byzantium
// ---- // ----
// test_eq_ok() -> 1 // test_eq_ok() -> 1
// test_eq() -> FAILURE # both should throw # // test_eq() -> FAILURE, hex"4e487b71", 33 # both should throw #
// test_neq() -> FAILURE // test_neq() -> FAILURE, hex"4e487b71", 33

View File

@ -16,8 +16,9 @@ contract C {
return 1; return 1;
} }
} }
// ====
// EVMVersion: >=byzantium
// ---- // ----
// test_store_ok() -> 1 // test_store_ok() -> 1
// x() -> 0 // x() -> 0
// test_store() -> FAILURE # should throw # // test_store() -> FAILURE, hex"4e487b71", 33 # should throw #

View File

@ -14,12 +14,12 @@ contract C {
} }
} }
// ==== // ====
// compileViaYul: also
// EVMVersion: >homestead // EVMVersion: >homestead
// allowNonExistingFunctions: true // allowNonExistingFunctions: true
// compileViaYul: also
// ---- // ----
// _() -> FAILURE // _() -> FAILURE
// e() -> FAILURE, hex"08c379a0", 0x20, 19, "Transaction failed." // e() -> FAILURE, hex"08c379a0", 0x20, 0x13, "Transaction failed."
// f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0 // f(bool): false -> FAILURE, hex"08c379a0", 0x20, 0x00
// g(bool): false -> FAILURE, hex"08c379a0", 0x20, 15, "Value is false." // g(bool): false -> FAILURE, hex"08c379a0", 0x20, 0x0f, "Value is false."
// h() -> FAILURE // h() -> FAILURE, hex"4e487b71", 0x01

View File

@ -9,22 +9,24 @@ contract test {
} }
} }
// ==== // ====
// compileViaYul: also // EVMVersion: >=byzantium
// ABIEncoderV1Only: true
// compileViaYul: false
// ---- // ----
// get(uint8): 0 -> 0 // get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0 // get(uint8): 0x01 -> 0
// get(uint8): 0x02 -> 0 // get(uint8): 0x02 -> 0
// get(uint8): 0x03 -> FAILURE // get(uint8): 0x03 -> FAILURE, hex"4e487b71", 33
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x01, 0xa1 -> // set(uint8,uint8): 0x01, 0xa1 ->
// get(uint8): 0 -> 0 // get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0xa1 // get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x00, 0xef -> // set(uint8,uint8): 0x00, 0xef ->
// get(uint8): 0 -> 0xef // get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0xa1 // get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x01, 0x05 -> // set(uint8,uint8): 0x01, 0x05 ->
// get(uint8): 0 -> 0xef // get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0x05 // get(uint8): 0x01 -> 0x05
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33

View File

@ -10,31 +10,32 @@ contract test {
} }
// ==== // ====
// ABIEncoderV1Only: true // ABIEncoderV1Only: true
// EVMVersion: >=byzantium
// ---- // ----
// table(uint8): 0 -> 0 // table(uint8): 0 -> 0
// table(uint8): 0x01 -> 0 // table(uint8): 0x01 -> 0
// table(uint8): 0xa7 -> 0 // table(uint8): 0xa7 -> 0
// get(uint8): 0 -> 0 // get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0 // get(uint8): 0x01 -> 0
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x01, 0xa1 -> // set(uint8,uint8): 0x01, 0xa1 ->
// table(uint8): 0 -> 0 // table(uint8): 0 -> 0
// table(uint8): 0x01 -> 0xa1 // table(uint8): 0x01 -> 0xa1
// table(uint8): 0xa7 -> 0 // table(uint8): 0xa7 -> 0
// get(uint8): 0 -> 0 // get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0xa1 // get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x00, 0xef -> // set(uint8,uint8): 0x00, 0xef ->
// table(uint8): 0 -> 0xef // table(uint8): 0 -> 0xef
// table(uint8): 0x01 -> 0xa1 // table(uint8): 0x01 -> 0xa1
// table(uint8): 0xa7 -> 0 // table(uint8): 0xa7 -> 0
// get(uint8): 0 -> 0xef // get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0xa1 // get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x01, 0x05 -> // set(uint8,uint8): 0x01, 0x05 ->
// table(uint8): 0 -> 0xef // table(uint8): 0 -> 0xef
// table(uint8): 0x01 -> 0x05 // table(uint8): 0x01 -> 0x05
// table(uint8): 0xa7 -> 0 // table(uint8): 0xa7 -> 0
// get(uint8): 0 -> 0xef // get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0x05 // get(uint8): 0x01 -> 0x05
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33

View File

@ -16,20 +16,23 @@ contract test {
L.set(table, k, v); L.set(table, k, v);
} }
} }
// ====
// EVMVersion: >=byzantium
// ABIEncoderV1Only: true
// ---- // ----
// library: L // library: L
// get(uint8): 0 -> 0 // get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0 // get(uint8): 0x01 -> 0
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x01, 0xa1 -> // set(uint8,uint8): 0x01, 0xa1 ->
// get(uint8): 0 -> 0 // get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0xa1 // get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x00, 0xef -> // set(uint8,uint8): 0x00, 0xef ->
// get(uint8): 0 -> 0xef // get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0xa1 // get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33
// set(uint8,uint8): 0x01, 0x05 -> // set(uint8,uint8): 0x01, 0x05 ->
// get(uint8): 0 -> 0xef // get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0x05 // get(uint8): 0x01 -> 0x05
// get(uint8): 0xa7 -> FAILURE // get(uint8): 0xa7 -> FAILURE, hex"4e487b71", 33

View File

@ -0,0 +1,39 @@
pragma experimental ABIEncoderV2;
enum E { A, B, C }
library L {
function get(mapping(E => uint8) storage table, E k) external returns (uint8) {
return table[k];
}
function set(mapping(E => uint8) storage table, E k, uint8 v) external {
table[k] = v;
}
}
contract test {
mapping(E => uint8) table;
function get(E k) public returns (uint8 v) {
return L.get(table, k);
}
function set(E k, uint8 v) public {
L.set(table, k, v);
}
}
// ====
// EVMVersion: >=byzantium
// ----
// library: L
// get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0
// get(uint8): 0xa7 -> FAILURE
// set(uint8,uint8): 0x01, 0xa1 ->
// get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE
// set(uint8,uint8): 0x00, 0xef ->
// get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE
// set(uint8,uint8): 0x01, 0x05 ->
// get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0x05
// get(uint8): 0xa7 -> FAILURE

View File

@ -0,0 +1,32 @@
pragma experimental ABIEncoderV2;
enum E { A, B, C }
contract test {
mapping(E => uint8) table;
function get(E k) public returns (uint8 v) {
return table[k];
}
function set(E k, uint8 v) public {
table[k] = v;
}
}
// ====
// compileViaYul: also
// EVMVersion: >=byzantium
// ----
// get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0
// get(uint8): 0x02 -> 0
// get(uint8): 0x03 -> FAILURE
// get(uint8): 0xa7 -> FAILURE
// set(uint8,uint8): 0x01, 0xa1 ->
// get(uint8): 0 -> 0
// get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE
// set(uint8,uint8): 0x00, 0xef ->
// get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0xa1
// get(uint8): 0xa7 -> FAILURE
// set(uint8,uint8): 0x01, 0x05 ->
// get(uint8): 0 -> 0xef
// get(uint8): 0x01 -> 0x05
// get(uint8): 0xa7 -> FAILURE

View File

@ -20,4 +20,4 @@ contract Test {
} }
} }
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x51

View File

@ -20,4 +20,4 @@ contract Test {
} }
} }
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x51

View File

@ -36,4 +36,4 @@ contract InvalidTest {
} }
} }
// ---- // ----
// run() -> FAILURE // run() -> FAILURE, hex"4e487b71", 0x51

View File

@ -15,5 +15,5 @@ contract InvalidTest {
} }
} }
// ---- // ----
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x51
// f() -> FAILURE // f() -> FAILURE, hex"4e487b71", 0x51

View File

@ -20,5 +20,5 @@ contract C {
// ---- // ----
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 0, 0, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 0, 0, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 3, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 3, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 3, 3, 32, "01234567890123456789012345678901" -> FAILURE // set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 3, 3, 32, "01234567890123456789012345678901" -> FAILURE, hex"4e487b71", 0x32
// set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 5, 32, "01234567890123456789012345678901" -> FAILURE // set(string,uint256,uint256,uint256,uint256): 0xa0, 2, 4, 1, 5, 32, "01234567890123456789012345678901" -> FAILURE, hex"4e487b71", 0x32

View File

@ -18,5 +18,5 @@ contract C {
// ---- // ----
// set(string,uint256,uint256): 0x60, 2, 0, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256): 0x60, 2, 0, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256): 0x60, 2, 1, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256): 0x60, 2, 1, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256): 0x60, 2, 2, 32, "01234567890123456789012345678901" -> FAILURE // set(string,uint256,uint256): 0x60, 2, 2, 32, "01234567890123456789012345678901" -> FAILURE, hex"4e487b71", 0x32
// set(string,uint256,uint256): 0x60, 200, 199, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256): 0x60, 200, 199, 32, "01234567890123456789012345678901" -> 0

View File

@ -19,4 +19,4 @@ contract C {
// set(string,uint256,uint256): 0x60, 5, 0, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256): 0x60, 5, 0, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256): 0x60, 5, 1, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256): 0x60, 5, 1, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256): 0x60, 5, 4, 32, "01234567890123456789012345678901" -> 0 // set(string,uint256,uint256): 0x60, 5, 4, 32, "01234567890123456789012345678901" -> 0
// set(string,uint256,uint256): 0x60, 5, 5, 32, "01234567890123456789012345678901" -> FAILURE // set(string,uint256,uint256): 0x60, 5, 5, 32, "01234567890123456789012345678901" -> FAILURE, hex"4e487b71", 0x32

View File

@ -20,7 +20,7 @@ contract C {
// ==== // ====
// compileViaYul: true // compileViaYul: true
// ---- // ----
// test(uint256,uint256): 0,0 -> FAILURE // test(uint256,uint256): 0, 0 -> FAILURE, hex"4e487b71", 0x32
// test(uint256,uint256): 1,0 -> 1 // test(uint256,uint256): 1, 0 -> 1
// test(uint256,uint256): 10,5 -> 6 // test(uint256,uint256): 10, 5 -> 6
// test(uint256,uint256): 10,50 -> FAILURE // test(uint256,uint256): 10, 50 -> FAILURE, hex"4e487b71", 0x32

View File

@ -28,8 +28,8 @@ contract C {
// index(uint256): 10 -> true // index(uint256): 10 -> true
// index(uint256): 20 -> true // index(uint256): 20 -> true
// index(uint256): 0xFF -> true // index(uint256): 0xFF -> true
// accessIndex(uint256,int256): 10,1 -> 2 // accessIndex(uint256,int256): 10, 1 -> 2
// accessIndex(uint256,int256): 10,0 -> 1 // accessIndex(uint256,int256): 10, 0 -> 1
// accessIndex(uint256,int256): 10,11 -> FAILURE // accessIndex(uint256,int256): 10, 11 -> FAILURE, hex"4e487b71", 0x32
// accessIndex(uint256,int256): 10,10 -> FAILURE // accessIndex(uint256,int256): 10, 10 -> FAILURE, hex"4e487b71", 0x32
// accessIndex(uint256,int256): 10,-1 -> FAILURE // accessIndex(uint256,int256): 10, -1 -> FAILURE, hex"4e487b71", 0x32

View File

@ -17,9 +17,9 @@ contract C {
// test(uint256): 42 -> // test(uint256): 42 ->
// getLength() -> 1 // getLength() -> 1
// fetch(uint256): 0 -> 42 // fetch(uint256): 0 -> 42
// fetch(uint256): 1 -> FAILURE // fetch(uint256): 1 -> FAILURE, hex"4e487b71", 0x32
// test(uint256): 23 -> // test(uint256): 23 ->
// getLength() -> 2 // getLength() -> 2
// fetch(uint256): 0 -> 42 // fetch(uint256): 0 -> 42
// fetch(uint256): 1 -> 23 // fetch(uint256): 1 -> 23
// fetch(uint256): 2 -> FAILURE // fetch(uint256): 2 -> FAILURE, hex"4e487b71", 0x32

View File

@ -17,9 +17,9 @@ contract C {
// test(uint256): 42 -> // test(uint256): 42 ->
// getLength() -> 1 // getLength() -> 1
// fetch(uint256): 0 -> 42 // fetch(uint256): 0 -> 42
// fetch(uint256): 1 -> FAILURE // fetch(uint256): 1 -> FAILURE, hex"4e487b71", 0x32
// test(uint256): 23 -> // test(uint256): 23 ->
// getLength() -> 2 // getLength() -> 2
// fetch(uint256): 0 -> 42 // fetch(uint256): 0 -> 42
// fetch(uint256): 1 -> 23 // fetch(uint256): 1 -> 23
// fetch(uint256): 2 -> FAILURE // fetch(uint256): 2 -> FAILURE, hex"4e487b71", 0x32

View File

@ -12,12 +12,12 @@ contract C {
// ==== // ====
// compileViaYul: true // compileViaYul: true
// ---- // ----
// test_boundary_check(uint256, uint256): 10, 11 -> FAILURE // test_boundary_check(uint256,uint256): 10, 11 -> FAILURE, hex"4e487b71", 0x32
// test_boundary_check(uint256, uint256): 10, 9 -> 0 // test_boundary_check(uint256,uint256): 10, 9 -> 0
// test_boundary_check(uint256, uint256): 1, 9 -> FAILURE // test_boundary_check(uint256,uint256): 1, 9 -> FAILURE, hex"4e487b71", 0x32
// test_boundary_check(uint256, uint256): 1, 1 -> FAILURE // test_boundary_check(uint256,uint256): 1, 1 -> FAILURE, hex"4e487b71", 0x32
// test_boundary_check(uint256, uint256): 10, 10 -> FAILURE // test_boundary_check(uint256,uint256): 10, 10 -> FAILURE, hex"4e487b71", 0x32
// test_boundary_check(uint256, uint256): 256, 256 -> FAILURE // test_boundary_check(uint256,uint256): 256, 256 -> FAILURE, hex"4e487b71", 0x32
// test_boundary_check(uint256, uint256): 256, 255 -> 0 // test_boundary_check(uint256,uint256): 256, 255 -> 0
// test_boundary_check(uint256, uint256): 256, 0xFFFF -> FAILURE // test_boundary_check(uint256,uint256): 256, 0xFFFF -> FAILURE, hex"4e487b71", 0x32
// test_boundary_check(uint256, uint256): 256, 2 -> 0 // test_boundary_check(uint256,uint256): 256, 2 -> 0

View File

@ -8,4 +8,4 @@ contract C {
// EVMVersion: >=petersburg // EVMVersion: >=petersburg
// compileViaYul: true // compileViaYul: true
// ---- // ----
// popEmpty() -> FAILURE // popEmpty() -> FAILURE, hex"4e487b71", 0x31

Some files were not shown because too many files have changed in this diff Show More