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
23 changed files with 141 additions and 174 deletions
+1
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:
+2
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)``.
+3 -3
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:
+1 -1
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
+4 -4
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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