mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10013 from ethereum/errorCodesPanic
Panic with error codes.
This commit is contained in:
commit
f22cb64710
@ -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:
|
||||||
|
@ -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
|
||||||
======================
|
======================
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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.
|
||||||
|
@ -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
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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 = "");
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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));
|
||||||
|
|
||||||
|
@ -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())
|
||||||
|
@ -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
38
libsolutil/ErrorCodes.h
Normal 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
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -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);
|
||||||
|
@ -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};
|
||||||
|
@ -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>
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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) }
|
||||||
}
|
}
|
||||||
|
@ -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
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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));
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -14,5 +14,5 @@ contract D {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x11
|
||||||
// g(), 100 wei -> 1
|
// g(), 100 wei -> 1
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 #
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 #
|
||||||
|
@ -9,4 +9,4 @@ contract c {
|
|||||||
// ====
|
// ====
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> FAILURE
|
// test() -> FAILURE, hex"4e487b71", 0x31
|
||||||
|
@ -12,4 +12,4 @@ contract c {
|
|||||||
// ====
|
// ====
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> FAILURE
|
// test() -> FAILURE, hex"4e487b71", 0x31
|
||||||
|
@ -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
|
||||||
|
@ -19,4 +19,4 @@ contract C {
|
|||||||
|
|
||||||
// ----
|
// ----
|
||||||
// one() -> 3
|
// one() -> 3
|
||||||
// two() -> FAILURE
|
// two() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -22,5 +22,5 @@ contract C {
|
|||||||
// ====
|
// ====
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x41
|
||||||
// g() -> FAILURE
|
// g() -> FAILURE, hex"4e487b71", 0x41
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
@ -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
|
||||||
|
@ -17,4 +17,4 @@ contract C {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
// t() -> FAILURE
|
// t() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -18,4 +18,4 @@ contract C {
|
|||||||
// ====
|
// ====
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// t() -> FAILURE
|
// t() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -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
|
||||||
|
@ -8,4 +8,4 @@ contract test {
|
|||||||
// ----
|
// ----
|
||||||
// f() ->
|
// f() ->
|
||||||
// g() -> FAILURE
|
// g() -> FAILURE
|
||||||
// h() -> FAILURE
|
// h() -> FAILURE, hex"4e487b71", 0x01
|
||||||
|
@ -13,4 +13,4 @@ contract C {
|
|||||||
// ====
|
// ====
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> FAILURE
|
// test() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -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
|
||||||
|
@ -8,4 +8,4 @@ contract Test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -16,6 +16,6 @@ contract C {
|
|||||||
|
|
||||||
// ----
|
// ----
|
||||||
// g() -> 2
|
// g() -> 2
|
||||||
// h() -> FAILURE
|
// h() -> FAILURE, hex"4e487b71", 0x51
|
||||||
// set() ->
|
// set() ->
|
||||||
// h() -> 2
|
// h() -> 2
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -16,6 +16,7 @@ contract C {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ====
|
// ====
|
||||||
|
// EVMVersion: >=byzantium
|
||||||
// compileViaYul: also
|
// compileViaYul: also
|
||||||
// ----
|
// ----
|
||||||
// test() -> FAILURE # should throw #
|
// test() -> FAILURE, hex"4e487b71", 33 # should throw #
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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 #
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
32
test/libsolidity/semanticTests/types/mapping_enum_key_v2.sol
Normal file
32
test/libsolidity/semanticTests/types/mapping_enum_key_v2.sol
Normal 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
|
@ -20,4 +20,4 @@ contract Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -20,4 +20,4 @@ contract Test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -36,4 +36,4 @@ contract InvalidTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// run() -> FAILURE
|
// run() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -15,5 +15,5 @@ contract InvalidTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x51
|
||||||
// f() -> FAILURE
|
// f() -> FAILURE, hex"4e487b71", 0x51
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
Loading…
Reference in New Issue
Block a user