Merge pull request #8901 from mijovic/dissalowShiftsBySignedArguments

[BREAKING] Disallowing shifts by signed types
This commit is contained in:
chriseth 2020-05-26 11:51:10 +02:00 committed by GitHub
commit 189d30b3ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 141 additions and 174 deletions

View File

@ -5,6 +5,7 @@ Breaking changes:
* Deprecated dot syntax for `value` and `gas`.
* Deprecated the identifier `now`.
* JSON AST: Removes members with ``null`` value from JSON output.
* Type Checker: Disallow shifts by signed types.
Language Features:

View File

@ -16,3 +16,5 @@ This section gives detailed instructions on how to update prior code for every b
* Change ``f.value(...)()`` to ``f{value: ...}()``. Similarly ``(new C).value(...)()`` to
``(new C){value: ...}()`` and ``f.gas(...)()`` to ``f{gas: ...}()``.
* Change ``now`` to ``block.timestamp``.
* Change types of right operand in shift operators to unsigned types. For example change ``x >> (256 - y)`` to
``x >> uint(256 - y)``.

View File

@ -64,11 +64,11 @@ Shifts
^^^^^^
The result of a shift operation has the type of the left operand, truncating the result to match the type.
Right operand must be unsigned type. Trying to shift by signed type will produce a compilation error.
- For positive and negative ``x`` values, ``x << y`` is equivalent to ``x * 2**y``.
- For positive ``x`` values, ``x >> y`` is equivalent to ``x / 2**y``.
- For negative ``x`` values, ``x >> y`` is equivalent to ``(x + 1) / 2**y - 1`` (which is the same as dividing ``x`` by ``2**y`` while rounding down towards negative infinity).
- In all cases, shifting by a negative ``y`` throws a runtime exception.
.. warning::
Before version ``0.5.0`` a right shift ``x >> y`` for negative ``x`` was equivalent to ``x / 2**y``,
@ -370,9 +370,9 @@ Operators:
* Shift operators: ``<<`` (left shift), ``>>`` (right shift)
* Index access: If ``x`` is of type ``bytesI``, then ``x[k]`` for ``0 <= k < I`` returns the ``k`` th byte (read-only).
The shifting operator works with any integer type as right operand (but
The shifting operator works with unsigned integer type as right operand (but
returns the type of the left operand), which denotes the number of bits to shift by.
Shifting by a negative amount causes a runtime exception.
Shifting by a signed type will produce a compilation error.
Members:

View File

@ -480,7 +480,7 @@ bool isValidShiftAndAmountType(Token _operator, Type const& _shiftAmountType)
if (_operator == Token::SHR)
return false;
else if (IntegerType const* otherInt = dynamic_cast<decltype(otherInt)>(&_shiftAmountType))
return true;
return !otherInt->isSigned();
else if (RationalNumberType const* otherRat = dynamic_cast<decltype(otherRat)>(&_shiftAmountType))
return !otherRat->isFractional() && otherRat->integerType() && !otherRat->integerType()->isSigned();
else

View File

@ -94,12 +94,12 @@ library Math {
zpow = zpow * z / ONE;
result += 0x9c7 * zpow / ONE;
if (shift >= 0) {
if (result >> (256-shift) > 0)
return (2**256-1);
return result << shift;
if (result >> uint(256 - shift) > 0)
return (2 ** 256 - 1);
return result << uint(shift);
}
else
return result >> (-shift);
return result >> uint(-shift);
}
/// @dev Returns natural logarithm value of given x

View File

@ -1,15 +0,0 @@
contract C {
function f(int256 a, int256 b) public returns (int256) {
return a << b;
}
function g(int256 a, int256 b) public returns (int256) {
return a >> b;
}
}
// ====
// compileViaYul: also
// ----
// f(int256,int256): 1, -1 -> FAILURE
// g(int256,int256): 1, -1 -> FAILURE

View File

@ -1,17 +0,0 @@
contract C {
function f(int256 a, int256 b) public returns (int256) {
a <<= b;
return a;
}
function g(int256 a, int256 b) public returns (int256) {
a >>= b;
return a;
}
}
// ====
// compileViaYul: also
// ----
// f(int256,int256): 1, -1 -> FAILURE
// g(int256,int256): 1, -1 -> FAILURE

View File

@ -3,7 +3,7 @@ contract C {
return x << y;
}
function leftS(int8 x, int8 y) public returns (int8) {
function leftS(int8 x, uint8 y) public returns (int8) {
return x << y;
}
}
@ -14,5 +14,5 @@ contract C {
// leftU(uint8,uint8): 255, 8 -> 0
// leftU(uint8,uint8): 255, 1 -> 254
// leftU(uint8,uint8): 255, 0 -> 255
// leftS(int8,int8): 1, 7 -> -128 # Result is -128 and output is sign-extended, not zero-padded. #
// leftS(int8,int8): 1, 6 -> 64
// leftS(int8,uint8): 1, 7 -> -128 # Result is -128 and output is sign-extended, not zero-padded. #
// leftS(int8,uint8): 1, 6 -> 64

View File

@ -1,14 +0,0 @@
contract C {
function f(int256 a, int256 b) public returns (int256) {
a >>= b;
return a;
}
}
// ====
// compileViaYul: also
// ----
// f(int256,int256): 0x4266, 0x0 -> 0x4266
// f(int256,int256): 0x4266, 0x8 -> 0x42
// f(int256,int256): 0x4266, 0x10 -> 0
// f(int256,int256): 0x4266, 0x11 -> 0

View File

@ -1,5 +1,5 @@
contract C {
function f(int256 a, int256 b) public returns (int256) {
function f(int256 a, uint256 b) public returns (int256) {
return a >> b;
}
}
@ -7,15 +7,15 @@ contract C {
// ====
// compileViaYul: also
// ----
// f(int256,int256): -4266, 0 -> -4266
// f(int256,int256): -4266, 1 -> -2133
// f(int256,int256): -4266, 4 -> -267
// f(int256,int256): -4266, 8 -> -17
// f(int256,int256): -4266, 16 -> -1
// f(int256,int256): -4266, 17 -> -1
// f(int256,int256): -4267, 0 -> -4267
// f(int256,int256): -4267, 1 -> -2134
// f(int256,int256): -4267, 4 -> -267
// f(int256,int256): -4267, 8 -> -17
// f(int256,int256): -4267, 16 -> -1
// f(int256,int256): -4267, 17 -> -1
// f(int256,uint256): -4266, 0 -> -4266
// f(int256,uint256): -4266, 1 -> -2133
// f(int256,uint256): -4266, 4 -> -267
// f(int256,uint256): -4266, 8 -> -17
// f(int256,uint256): -4266, 16 -> -1
// f(int256,uint256): -4266, 17 -> -1
// f(int256,uint256): -4267, 0 -> -4267
// f(int256,uint256): -4267, 1 -> -2134
// f(int256,uint256): -4267, 4 -> -267
// f(int256,uint256): -4267, 8 -> -17
// f(int256,uint256): -4267, 16 -> -1
// f(int256,uint256): -4267, 17 -> -1

View File

@ -1,5 +1,5 @@
contract C {
function f(int256 a, int256 b) public returns (int256) {
function f(int256 a, uint256 b) public returns (int256) {
a >>= b;
return a;
}
@ -8,15 +8,15 @@ contract C {
// ====
// compileViaYul: also
// ----
// f(int256,int256): -4266, 0 -> -4266
// f(int256,int256): -4266, 1 -> -2133
// f(int256,int256): -4266, 4 -> -267
// f(int256,int256): -4266, 8 -> -17
// f(int256,int256): -4266, 16 -> -1
// f(int256,int256): -4266, 17 -> -1
// f(int256,int256): -4267, 0 -> -4267
// f(int256,int256): -4267, 1 -> -2134
// f(int256,int256): -4267, 4 -> -267
// f(int256,int256): -4267, 8 -> -17
// f(int256,int256): -4267, 16 -> -1
// f(int256,int256): -4267, 17 -> -1
// f(int256,uint256): -4266, 0 -> -4266
// f(int256,uint256): -4266, 1 -> -2133
// f(int256,uint256): -4266, 4 -> -267
// f(int256,uint256): -4266, 8 -> -17
// f(int256,uint256): -4266, 16 -> -1
// f(int256,uint256): -4266, 17 -> -1
// f(int256,uint256): -4267, 0 -> -4267
// f(int256,uint256): -4267, 1 -> -2134
// f(int256,uint256): -4267, 4 -> -267
// f(int256,uint256): -4267, 8 -> -17
// f(int256,uint256): -4267, 16 -> -1
// f(int256,uint256): -4267, 17 -> -1

View File

@ -1,5 +1,5 @@
contract C {
function f(int16 a, int16 b) public returns (int256) {
function f(int16 a, uint16 b) public returns (int256) {
return a >> b;
}
}
@ -7,15 +7,15 @@ contract C {
// ====
// compileViaYul: also
// ----
// f(int16,int16): -4266, 0 -> -4266
// f(int16,int16): -4266, 1 -> -2133
// f(int16,int16): -4266, 4 -> -267
// f(int16,int16): -4266, 8 -> -17
// f(int16,int16): -4266, 16 -> -1
// f(int16,int16): -4266, 17 -> -1
// f(int16,int16): -4267, 0 -> -4267
// f(int16,int16): -4267, 1 -> -2134
// f(int16,int16): -4267, 4 -> -267
// f(int16,int16): -4267, 8 -> -17
// f(int16,int16): -4267, 16 -> -1
// f(int16,int16): -4267, 17 -> -1
// f(int16,uint16): -4266, 0 -> -4266
// f(int16,uint16): -4266, 1 -> -2133
// f(int16,uint16): -4266, 4 -> -267
// f(int16,uint16): -4266, 8 -> -17
// f(int16,uint16): -4266, 16 -> -1
// f(int16,uint16): -4266, 17 -> -1
// f(int16,uint16): -4267, 0 -> -4267
// f(int16,uint16): -4267, 1 -> -2134
// f(int16,uint16): -4267, 4 -> -267
// f(int16,uint16): -4267, 8 -> -17
// f(int16,uint16): -4267, 16 -> -1
// f(int16,uint16): -4267, 17 -> -1

View File

@ -1,5 +1,5 @@
contract C {
function f(int32 a, int32 b) public returns (int256) {
function f(int32 a, uint32 b) public returns (int256) {
return a >> b;
}
}
@ -7,15 +7,15 @@ contract C {
// ====
// compileViaYul: also
// ----
// f(int32,int32): -4266, 0 -> -4266
// f(int32,int32): -4266, 1 -> -2133
// f(int32,int32): -4266, 4 -> -267
// f(int32,int32): -4266, 8 -> -17
// f(int32,int32): -4266, 16 -> -1
// f(int32,int32): -4266, 17 -> -1
// f(int32,int32): -4267, 0 -> -4267
// f(int32,int32): -4267, 1 -> -2134
// f(int32,int32): -4267, 4 -> -267
// f(int32,int32): -4267, 8 -> -17
// f(int32,int32): -4267, 16 -> -1
// f(int32,int32): -4267, 17 -> -1
// f(int32,uint32): -4266, 0 -> -4266
// f(int32,uint32): -4266, 1 -> -2133
// f(int32,uint32): -4266, 4 -> -267
// f(int32,uint32): -4266, 8 -> -17
// f(int32,uint32): -4266, 16 -> -1
// f(int32,uint32): -4266, 17 -> -1
// f(int32,uint32): -4267, 0 -> -4267
// f(int32,uint32): -4267, 1 -> -2134
// f(int32,uint32): -4267, 4 -> -267
// f(int32,uint32): -4267, 8 -> -17
// f(int32,uint32): -4267, 16 -> -1
// f(int32,uint32): -4267, 17 -> -1

View File

@ -1,5 +1,5 @@
contract C {
function f(int8 a, int8 b) public returns (int256) {
function f(int8 a, uint8 b) public returns (int256) {
return a >> b;
}
}
@ -7,15 +7,15 @@ contract C {
// ====
// compileViaYul: also
// ----
// f(int8,int8): -66, 0 -> -66
// f(int8,int8): -66, 1 -> -33
// f(int8,int8): -66, 4 -> -5
// f(int8,int8): -66, 8 -> -1
// f(int8,int8): -66, 16 -> -1
// f(int8,int8): -66, 17 -> -1
// f(int8,int8): -67, 0 -> -67
// f(int8,int8): -67, 1 -> -34
// f(int8,int8): -67, 4 -> -5
// f(int8,int8): -67, 8 -> -1
// f(int8,int8): -67, 16 -> -1
// f(int8,int8): -67, 17 -> -1
// f(int8,uint8): -66, 0 -> -66
// f(int8,uint8): -66, 1 -> -33
// f(int8,uint8): -66, 4 -> -5
// f(int8,uint8): -66, 8 -> -1
// f(int8,uint8): -66, 16 -> -1
// f(int8,uint8): -66, 17 -> -1
// f(int8,uint8): -67, 0 -> -67
// f(int8,uint8): -67, 1 -> -34
// f(int8,uint8): -67, 4 -> -5
// f(int8,uint8): -67, 8 -> -1
// f(int8,uint8): -67, 16 -> -1
// f(int8,uint8): -67, 17 -> -1

View File

@ -1,13 +1,13 @@
contract C {
function f(int16 a, int16 b) public returns (int16) {
function f(int16 a, uint16 b) public returns (int16) {
return a >> b;
}
}
// ====
// ABIEncoderV1Only: true
// ----
// f(int16,int16): 0xff99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99
// f(int16,int16): 0xff99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc
// f(int16,int16): 0xff99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6
// f(int16,int16): 0xff99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9
// f(int16,int16): 0xff99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// f(int16,uint16): 0xff99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99
// f(int16,uint16): 0xff99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc
// f(int16,uint16): 0xff99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6
// f(int16,uint16): 0xff99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9
// f(int16,uint16): 0xff99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

View File

@ -2,15 +2,15 @@ pragma experimental ABIEncoderV2;
contract C {
function f(int16 a, int16 b) public returns (int16) {
function f(int16 a, uint16 b) public returns (int16) {
return a >> b;
}
}
// ====
// compileViaYul: also
// ----
// f(int16,int16): 0xff99, 0x00 -> FAILURE
// f(int16,int16): 0xff99, 0x01 -> FAILURE
// f(int16,int16): 0xff99, 0x02 -> FAILURE
// f(int16,int16): 0xff99, 0x04 -> FAILURE
// f(int16,int16): 0xff99, 0x08 -> FAILURE
// f(int16,uint16): 0xff99, 0x00 -> FAILURE
// f(int16,uint16): 0xff99, 0x01 -> FAILURE
// f(int16,uint16): 0xff99, 0x02 -> FAILURE
// f(int16,uint16): 0xff99, 0x04 -> FAILURE
// f(int16,uint16): 0xff99, 0x08 -> FAILURE

View File

@ -1,13 +1,13 @@
contract C {
function f(int32 a, int32 b) public returns (int32) {
function f(int32 a, uint32 b) public returns (int32) {
return a >> b;
}
}
// ====
// ABIEncoderV1Only: true
// ----
// f(int32,int32): 0xffffff99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99
// f(int32,int32): 0xffffff99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc
// f(int32,int32): 0xffffff99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6
// f(int32,int32): 0xffffff99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9
// f(int32,int32): 0xffffff99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// f(int32,uint32): 0xffffff99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99
// f(int32,uint32): 0xffffff99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc
// f(int32,uint32): 0xffffff99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6
// f(int32,uint32): 0xffffff99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9
// f(int32,uint32): 0xffffff99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

View File

@ -2,15 +2,15 @@ pragma experimental ABIEncoderV2;
contract C {
function f(int32 a, int32 b) public returns (int32) {
function f(int32 a, uint32 b) public returns (int32) {
return a >> b;
}
}
// ====
// compileViaYul: also
// ----
// f(int32,int32): 0xffffff99, 0x00 -> FAILURE
// f(int32,int32): 0xffffff99, 0x01 -> FAILURE
// f(int32,int32): 0xffffff99, 0x02 -> FAILURE
// f(int32,int32): 0xffffff99, 0x04 -> FAILURE
// f(int32,int32): 0xffffff99, 0x08 -> FAILURE
// f(int32,uint32): 0xffffff99, 0x00 -> FAILURE
// f(int32,uint32): 0xffffff99, 0x01 -> FAILURE
// f(int32,uint32): 0xffffff99, 0x02 -> FAILURE
// f(int32,uint32): 0xffffff99, 0x04 -> FAILURE
// f(int32,uint32): 0xffffff99, 0x08 -> FAILURE

View File

@ -1,13 +1,13 @@
contract C {
function f(int8 a, int8 b) public returns (int8) {
function f(int8 a, uint8 b) public returns (int8) {
return a >> b;
}
}
// ====
// ABIEncoderV1Only: true
// ----
// f(int8,int8): 0x99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99
// f(int8,int8): 0x99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc
// f(int8,int8): 0x99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6
// f(int8,int8): 0x99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9
// f(int8,int8): 0x99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
// f(int8,uint8): 0x99, 0x00 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff99
// f(int8,uint8): 0x99, 0x01 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffcc
// f(int8,uint8): 0x99, 0x02 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe6
// f(int8,uint8): 0x99, 0x04 -> 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9
// f(int8,uint8): 0x99, 0x08 -> 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff

View File

@ -2,15 +2,15 @@ pragma experimental ABIEncoderV2;
contract C {
function f(int8 a, int8 b) public returns (int8) {
function f(int8 a, uint8 b) public returns (int8) {
return a >> b;
}
}
// ====
// compileViaYul: also
// ----
// f(int8,int8): 0x99, 0x00 -> FAILURE
// f(int8,int8): 0x99, 0x01 -> FAILURE
// f(int8,int8): 0x99, 0x02 -> FAILURE
// f(int8,int8): 0x99, 0x04 -> FAILURE
// f(int8,int8): 0x99, 0x08 -> FAILURE
// f(int8,uint8): 0x99, 0x00 -> FAILURE
// f(int8,uint8): 0x99, 0x01 -> FAILURE
// f(int8,uint8): 0x99, 0x02 -> FAILURE
// f(int8,uint8): 0x99, 0x04 -> FAILURE
// f(int8,uint8): 0x99, 0x08 -> FAILURE

View File

@ -1,16 +0,0 @@
contract C {
function f(uint256 a, int8 b) public returns (uint256) {
assembly { b := 0xff }
return a << b;
}
function g(uint256 a, int8 b) public returns (uint256) {
assembly { b := 0xff }
return a >> b;
}
}
// ====
// compileViaYul: also
// ----
// f(uint256,int8): 0x1234, 0x0 -> FAILURE
// g(uint256,int8): 0x1234, 0x0 -> FAILURE

View File

@ -0,0 +1,15 @@
contract C {
function f(int256 a, uint256 b) public returns (int256) {
return a << b;
}
function g(int256 a, uint256 b) public returns (int256) {
return a >> b;
}
}
// ====
// compileViaYul: also
// ----
// f(int256,uint256): 1, -1 -> 0
// g(int256,uint256): 1, -1 -> 0

View File

@ -0,0 +1,11 @@
contract C {
function f(int256 a, int256 b) public returns (int256) {
return a >> b;
}
function g(int256 a, int256 b) public returns (int256) {
return a >> (256 - b);
}
}
// ----
// TypeError: (89-95): Operator >> not compatible with types int256 and int256
// TypeError: (179-193): Operator >> not compatible with types int256 and int256