mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Documentation.
This commit is contained in:
parent
e61fa59593
commit
e262f47f21
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
Breaking Changes:
|
Breaking Changes:
|
||||||
* Assembler: The artificial ASSIGNIMMUTABLE opcode and the corresponding builtin in the "EVM with object access" dialect of Yul take the base offset of the code to modify as additional argument.
|
* Assembler: The artificial ASSIGNIMMUTABLE opcode and the corresponding builtin in the "EVM with object access" dialect of Yul take the base offset of the code to modify as additional argument.
|
||||||
|
* Code Generator: All arithmetic is checked by default. These checks can be disabled using ``unchecked { ... }``.
|
||||||
* 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)``.
|
||||||
|
@ -475,6 +475,69 @@ In any case, you will get a warning about the outer variable being shadowed.
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.. _unchecked:
|
||||||
|
|
||||||
|
Checked or Unchecked Arithmetic
|
||||||
|
===============================
|
||||||
|
|
||||||
|
An overflow or underflow is the situation where the resulting value of an arithmetic operation,
|
||||||
|
when executed on an unrestricted integer, falls outside the range of the result type.
|
||||||
|
|
||||||
|
Prior to Solidity 0.8.0, arithmetic operations would always wrap in case of
|
||||||
|
under- or overflow leading to widespread use of libraries that introduce
|
||||||
|
additional checks.
|
||||||
|
|
||||||
|
Since Solidity 0.8.0, all arithmetic operations revert on over- and underflow by default,
|
||||||
|
thus making the use of these libraries unnecessary.
|
||||||
|
|
||||||
|
To obtain the previous behaviour, an ``unchecked`` block can be used:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
// SPDX-License-Identifier: GPL-3.0
|
||||||
|
pragma solidity >0.7.99;
|
||||||
|
contract C {
|
||||||
|
function f(uint a, uint b) pure public returns (uint) {
|
||||||
|
// This addition will wrap on underflow.
|
||||||
|
unchecked { return a - b; }
|
||||||
|
}
|
||||||
|
function g(uint a, uint b) pure public returns (uint) {
|
||||||
|
// This addition will revert on underflow.
|
||||||
|
return a - b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
The call to ``f(2, 3)`` will return ``2**256-1``, while ``g(2, 3)`` will cause
|
||||||
|
a failing assertion.
|
||||||
|
|
||||||
|
The ``unchecked`` block can be used everywhere inside a block, but not as a replacement
|
||||||
|
for a block. It also cannot be nested.
|
||||||
|
|
||||||
|
The setting only affects the statements that are syntactically inside the block.
|
||||||
|
Functions called from within an ``unchecked`` block do not inherit the property.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
To avoid ambiguity, you cannot use ``_;`` inside an ``unchecked`` block.
|
||||||
|
|
||||||
|
The following operators will cause a failing assertion on overflow or underflow
|
||||||
|
and will wrap without an error if used inside an unchecked block:
|
||||||
|
|
||||||
|
``++``, ``--``, ``+``, binary ``-``, unary ``-``, ``*``, ``/``, ``%``, ``**``
|
||||||
|
|
||||||
|
``+=``, ``-=``, ``*=``, ``/=``, ``%=``
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
It is not possible to disable the check for division by zero
|
||||||
|
or modulo by zero using the ``unchecked`` block.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The second statement in ``int x = type(int).min; -x;`` will result in an overflow
|
||||||
|
because the negative range can hold one more value than the positive range.
|
||||||
|
|
||||||
|
Explicit type conversions will always truncate and never cause a failing assertion
|
||||||
|
with the exception of a conversion from an integer to an enum type.
|
||||||
|
|
||||||
.. index:: ! exception, ! throw, ! assert, ! require, ! revert, ! errors
|
.. index:: ! exception, ! throw, ! assert, ! require, ! revert, ! errors
|
||||||
|
|
||||||
.. _assert-and-require:
|
.. _assert-and-require:
|
||||||
@ -519,6 +582,7 @@ An ``assert``-style exception is generated in the following situations:
|
|||||||
#. 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``).
|
#. 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``).
|
||||||
#. If you access a fixed-length ``bytesN`` at a too large or negative index.
|
#. If you access a fixed-length ``bytesN`` at a too large or negative index.
|
||||||
#. If you divide or modulo by zero (e.g. ``5 / 0`` or ``23 % 0``).
|
#. 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.
|
||||||
#. If you convert a value too big or negative into an enum type.
|
#. If you convert a value too big or negative into an enum type.
|
||||||
#. If you call a zero-initialized variable of internal function type.
|
#. If you call a zero-initialized variable of internal function type.
|
||||||
#. If you call ``assert`` with an argument that evaluates to false.
|
#. If you call ``assert`` with an argument that evaluates to false.
|
||||||
|
@ -246,21 +246,32 @@ Two's Complement / Underflows / Overflows
|
|||||||
=========================================
|
=========================================
|
||||||
|
|
||||||
As in many programming languages, Solidity's integer types are not actually integers.
|
As in many programming languages, Solidity's integer types are not actually integers.
|
||||||
They resemble integers when the values are small, but behave differently if the numbers are larger.
|
They resemble integers when the values are small, but cannot represent arbitrarily large numbers.
|
||||||
For example, the following is true: ``uint8(255) + uint8(1) == 0``. This situation is called
|
|
||||||
an *overflow*. It occurs when an operation is performed that requires a fixed size variable
|
The following code causes an overflow because the result of the addition is too large
|
||||||
to store a number (or piece of data) that is outside the range of the variable's data type.
|
to be stored in the type ``uint8``:
|
||||||
An *underflow* is the converse situation: ``uint8(0) - uint8(1) == 255``.
|
|
||||||
|
::
|
||||||
|
|
||||||
|
uint8 x = 255;
|
||||||
|
uint8 y = 1;
|
||||||
|
return x + y;
|
||||||
|
|
||||||
|
Solidity has two modes in which it deals with these overflows: Checked and Unchecked or "wrapping" mode.
|
||||||
|
|
||||||
|
The default checked mode will detect overflows and cause a failing assertion. You can disable this check
|
||||||
|
using ``unchecked { ... }``, causing the overflow to be silently ignored. The above code would return
|
||||||
|
``0`` if wrapped in ``unchecked { ... }``.
|
||||||
|
|
||||||
|
Even in checked mode, do not assume you are protected from overflow bugs.
|
||||||
|
In this mode, overflows will always revert. If it is not possible to avoid the
|
||||||
|
overflow, this can lead to a smart contract being stuck in a certain state.
|
||||||
|
|
||||||
In general, read about the limits of two's complement representation, which even has some
|
In general, read about the limits of two's complement representation, which even has some
|
||||||
more special edge cases for signed numbers.
|
more special edge cases for signed numbers.
|
||||||
|
|
||||||
Try to use ``require`` to limit the size of inputs to a reasonable range and use the
|
Try to use ``require`` to limit the size of inputs to a reasonable range and use the
|
||||||
:ref:`SMT checker<smt_checker>` to find potential overflows, or use a library like
|
:ref:`SMT checker<smt_checker>` to find potential overflows.
|
||||||
`SafeMath <https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/math/SafeMath.sol>`_
|
|
||||||
if you want all overflows to cause a revert.
|
|
||||||
|
|
||||||
Code such as ``require((balanceOf[_to] + _value) >= balanceOf[_to])`` can also help you check if values are what you expect.
|
|
||||||
|
|
||||||
.. _clearing-mappings:
|
.. _clearing-mappings:
|
||||||
|
|
||||||
|
@ -46,8 +46,10 @@ access the minimum and maximum value representable by the type.
|
|||||||
.. warning::
|
.. warning::
|
||||||
|
|
||||||
Integers in Solidity are restricted to a certain range. For example, with ``uint32``, this is ``0`` up to ``2**32 - 1``.
|
Integers in Solidity are restricted to a certain range. For example, with ``uint32``, this is ``0`` up to ``2**32 - 1``.
|
||||||
If the result of some operation on those numbers does not fit inside this range, it is truncated. These truncations can have
|
There are two modes in which arithmetic is performed on these types: The "wrapping" or "unchecked" mode and the "checked" mode.
|
||||||
serious consequences that you should :ref:`be aware of and mitigate against<underflow-overflow>`.
|
By default, arithmetic is always "checked", which mean that if the result of an operation falls outside the value range
|
||||||
|
of the type, the call is reverted through a :ref:`failing assertion<assert-and-require>`. You can switch to "unchecked" mode
|
||||||
|
using ``unchecked { ... }``. More details can be found in the section about :ref:`unchecked <unchecked>`.
|
||||||
|
|
||||||
Comparisons
|
Comparisons
|
||||||
^^^^^^^^^^^
|
^^^^^^^^^^^
|
||||||
@ -77,23 +79,22 @@ Right operand must be unsigned type. Trying to shift by signed type will produce
|
|||||||
Addition, Subtraction and Multiplication
|
Addition, Subtraction and Multiplication
|
||||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Addition, subtraction and multiplication have the usual semantics.
|
Addition, subtraction and multiplication have the usual semantics, with two different
|
||||||
They wrap in two's complement representation, meaning that
|
modes in regard to over- and underflow:
|
||||||
for example ``uint256(0) - uint256(1) == 2**256 - 1``. You have to take these overflows
|
|
||||||
into account when designing safe smart contracts.
|
By default, all arithmetic is checked for under- or overflow, but this can be disabled
|
||||||
|
using the :ref:`unchecked block<unchecked>`, resulting in wrapping arithmetic. More details
|
||||||
|
can be found in that section.
|
||||||
|
|
||||||
The expression ``-x`` is equivalent to ``(T(0) - x)`` where
|
The expression ``-x`` is equivalent to ``(T(0) - x)`` where
|
||||||
``T`` is the type of ``x``. It can only be applied to signed types.
|
``T`` is the type of ``x``. It can only be applied to signed types.
|
||||||
The value of ``-x`` can be
|
The value of ``-x`` can be
|
||||||
positive if ``x`` is negative. There is another caveat also resulting
|
positive if ``x`` is negative. There is another caveat also resulting
|
||||||
from two's complement representation::
|
from two's complement representation:
|
||||||
|
|
||||||
int x = -2**255;
|
|
||||||
assert(-x == x);
|
|
||||||
|
|
||||||
This means that even if a number is negative, you cannot assume that
|
|
||||||
its negation will be positive.
|
|
||||||
|
|
||||||
|
If you have ``int x = type(int).min;``, then ``-x`` does not fit the positive range.
|
||||||
|
This means that ``unchecked { assert(-x == x); }`` works, and the expression ``-x``
|
||||||
|
when used in checked mode will result in a failing assertion.
|
||||||
|
|
||||||
Division
|
Division
|
||||||
^^^^^^^^
|
^^^^^^^^
|
||||||
@ -106,7 +107,12 @@ 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.
|
Division by zero causes a failing assert. This check can **not** be disabled through ``unchecked { ... }``.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
The expression ``type(int).min / (-1)`` is the only case where division causes an overflow.
|
||||||
|
In checked arithmetic mode, this will cause a failing assertion, while in wrapping
|
||||||
|
mode, the value will be ``type(int).min``.
|
||||||
|
|
||||||
Modulo
|
Modulo
|
||||||
^^^^^^
|
^^^^^^
|
||||||
@ -121,14 +127,19 @@ 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.
|
Modulo with zero causes a failing assert. This check can **not** be disabled through ``unchecked { ... }``.
|
||||||
|
|
||||||
Exponentiation
|
Exponentiation
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
Exponentiation is only available for unsigned types in the exponent. The resulting type
|
Exponentiation is only available for unsigned types in the exponent. The resulting type
|
||||||
of an exponentiation is always equal to the type of the base. Please take care that it is
|
of an exponentiation is always equal to the type of the base. Please take care that it is
|
||||||
large enough to hold the result and prepare for potential wrapping behaviour.
|
large enough to hold the result and prepare for potential assertion failures or wrapping behaviour.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
In checked mode, exponentiation only uses the comparatively cheap ``exp`` opcode for small bases.
|
||||||
|
For the cases of ``x**3``, the expression ``x*x*x`` might be cheaper.
|
||||||
|
In any case, gas cost tests and the use of the optimizer are advisable.
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
Note that ``0**0`` is defined by the EVM as ``1``.
|
Note that ``0**0`` is defined by the EVM as ``1``.
|
||||||
|
Loading…
Reference in New Issue
Block a user