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:
|
||||
* 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: 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)``.
|
||||
|
@ -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
|
||||
|
||||
.. _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 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 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 call a zero-initialized variable of internal function type.
|
||||
#. 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.
|
||||
They resemble integers when the values are small, but behave differently if the numbers are larger.
|
||||
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
|
||||
to store a number (or piece of data) that is outside the range of the variable's data type.
|
||||
An *underflow* is the converse situation: ``uint8(0) - uint8(1) == 255``.
|
||||
They resemble integers when the values are small, but cannot represent arbitrarily large numbers.
|
||||
|
||||
The following code causes an overflow because the result of the addition is too large
|
||||
to be stored in the type ``uint8``:
|
||||
|
||||
::
|
||||
|
||||
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
|
||||
more special edge cases for signed numbers.
|
||||
|
||||
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
|
||||
`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.
|
||||
:ref:`SMT checker<smt_checker>` to find potential overflows.
|
||||
|
||||
.. _clearing-mappings:
|
||||
|
||||
|
@ -46,8 +46,10 @@ access the minimum and maximum value representable by the type.
|
||||
.. warning::
|
||||
|
||||
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
|
||||
serious consequences that you should :ref:`be aware of and mitigate against<underflow-overflow>`.
|
||||
There are two modes in which arithmetic is performed on these types: The "wrapping" or "unchecked" mode and the "checked" mode.
|
||||
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
|
||||
^^^^^^^^^^^
|
||||
@ -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 have the usual semantics.
|
||||
They wrap in two's complement representation, meaning that
|
||||
for example ``uint256(0) - uint256(1) == 2**256 - 1``. You have to take these overflows
|
||||
into account when designing safe smart contracts.
|
||||
Addition, subtraction and multiplication have the usual semantics, with two different
|
||||
modes in regard to over- and underflow:
|
||||
|
||||
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
|
||||
``T`` is the type of ``x``. It can only be applied to signed types.
|
||||
The value of ``-x`` can be
|
||||
positive if ``x`` is negative. There is another caveat also resulting
|
||||
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.
|
||||
from two's complement representation:
|
||||
|
||||
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
|
||||
^^^^^^^^
|
||||
@ -106,7 +107,12 @@ Note that in contrast, division on :ref:`literals<rational_literals>` results in
|
||||
of arbitrary precision.
|
||||
|
||||
.. 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
|
||||
^^^^^^
|
||||
@ -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)``
|
||||
|
||||
.. 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 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
|
||||
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 that ``0**0`` is defined by the EVM as ``1``.
|
||||
|
Loading…
Reference in New Issue
Block a user