Skip to content

Commit 6a57276

Browse files
authored
Merge pull request #8034 from ethereum/release_0515
Backport yul loop fix into 0.5.
2 parents 01f1aaa + f913406 commit 6a57276

File tree

10 files changed

+146
-12
lines changed

10 files changed

+146
-12
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ include(EthPolicy)
1010
eth_policy()
1111

1212
# project name and version should be set after cmake_policy CMP0048
13-
set(PROJECT_VERSION "0.5.14")
13+
set(PROJECT_VERSION "0.5.15")
1414
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)
1515

1616
include(TestBigEndian)

Changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
### 0.5.15 (2019-12-17)
2+
3+
Bugfixes:
4+
* Yul Optimizer: Fix incorrect redundant load optimization crossing user-defined functions that contain for-loops with memory / storage writes.
5+
6+
17
### 0.5.14 (2019-12-09)
28

39
Language Features:

docs/bugs.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11
[
2+
{
3+
"name": "ABIEncoderV2LoopYulOptimizer",
4+
"summary": "If both the experimental ABIEncoderV2 and the experimental Yul optimizer are activated, one component of the Yul optimizer may reuse data in memory that has been changed in the meantime.",
5+
"description": "The Yul optimizer incorrectly replaces ``mload`` and ``sload`` calls with values that have been previously written to the load location (and potentially changed in the meantime) if all of the following conditions are met: (1) there is a matching ``mstore`` or ``sstore`` call before; (2) the contents of memory or storage is only changed in a function that is called (directly or indirectly) in between the first store and the load call; (3) called function contains a for loop where the same memory location is changed in the condition or the post or body block. When used in Solidity mode, this can only happen if the experimental ABIEncoderV2 is activated and the experimental Yul optimizer has been activated manually in addition to the regular optimizer in the compiler settings.",
6+
"introduced": "0.5.14",
7+
"fixed": "0.5.15",
8+
"severity": "low",
9+
"conditions": {
10+
"ABIEncoderV2": true,
11+
"optimizer": true,
12+
"yulOptimizer": true
13+
}
14+
},
215
{
316
"name": "ABIEncoderV2CalldataStructsWithStaticallySizedAndDynamicallyEncodedMembers",
417
"summary": "Reading from calldata structs that contain dynamically encoded, but statically-sized members can result in incorrect values.",

docs/bugs_by_version.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -759,9 +759,15 @@
759759
"released": "2019-11-14"
760760
},
761761
"0.5.14": {
762-
"bugs": [],
762+
"bugs": [
763+
"ABIEncoderV2LoopYulOptimizer"
764+
],
763765
"released": "2019-12-09"
764766
},
767+
"0.5.15": {
768+
"bugs": [],
769+
"released": "2019-12-17"
770+
},
765771
"0.5.2": {
766772
"bugs": [
767773
"SignedArrayStorageCopy",

libyul/optimiser/CallGraphGenerator.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,10 @@ void CallGraphGenerator::operator()(FunctionCall const& _functionCall)
5050
ASTWalker::operator()(_functionCall);
5151
}
5252

53-
void CallGraphGenerator::operator()(ForLoop const&)
53+
void CallGraphGenerator::operator()(ForLoop const& _forLoop)
5454
{
5555
m_callGraph.functionsWithLoops.insert(m_currentFunction);
56+
ASTWalker::operator()(_forLoop);
5657
}
5758

5859
void CallGraphGenerator::operator()(FunctionDefinition const& _functionDefinition)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
function foo(x) {
3+
for {} x { x := mload(0) mstore(0, 0)} {}
4+
}
5+
mstore(0, 1337)
6+
foo(42)
7+
sstore(0, mload(0))
8+
}
9+
// ----
10+
// : invalidatesStorage, invalidatesMemory
11+
// foo: invalidatesMemory

test/libyul/yulOptimizerTests/fullSuite/abi_example1.yul

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -477,15 +477,16 @@
477477
// pos := add(pos, 0x60)
478478
// }
479479
// let _3 := mload(64)
480-
// if slt(sub(_3, length), 128) { revert(_1, _1) }
481-
// let offset := calldataload(add(length, 64))
482-
// let _4 := 0xffffffffffffffff
483-
// if gt(offset, _4) { revert(_1, _1) }
484-
// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(length, offset), _3)
485-
// let offset_1 := calldataload(add(length, 0x60))
486-
// if gt(offset_1, _4) { revert(_1, _1) }
487-
// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(length, offset_1), _3)
488-
// sstore(calldataload(length), calldataload(add(length, 0x20)))
480+
// let _4 := mload(0x20)
481+
// if slt(sub(_3, _4), 128) { revert(_1, _1) }
482+
// let offset := calldataload(add(_4, 64))
483+
// let _5 := 0xffffffffffffffff
484+
// if gt(offset, _5) { revert(_1, _1) }
485+
// let value2 := abi_decode_t_array$_t_uint256_$dyn_memory_ptr(add(_4, offset), _3)
486+
// let offset_1 := calldataload(add(_4, 0x60))
487+
// if gt(offset_1, _5) { revert(_1, _1) }
488+
// let value3 := abi_decode_t_array$_t_array$_t_uint256_$2_memory_$dyn_memory_ptr(add(_4, offset_1), _3)
489+
// sstore(calldataload(_4), calldataload(add(_4, 0x20)))
489490
// sstore(value2, value3)
490491
// sstore(_1, pos)
491492
// }
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
function foo(x) {
3+
for {} x { x := mload(0) mstore(0, 0)} {}
4+
}
5+
mstore(0, 1337)
6+
foo(42)
7+
sstore(0, mload(0))
8+
}
9+
// ====
10+
// step: loadResolver
11+
// ----
12+
// {
13+
// function foo(x)
14+
// {
15+
// for { }
16+
// x
17+
// {
18+
// let _1 := 0
19+
// x := mload(_1)
20+
// mstore(_1, _1)
21+
// }
22+
// { }
23+
// }
24+
// let _4 := 1337
25+
// let _5 := 0
26+
// mstore(_5, _4)
27+
// foo(42)
28+
// sstore(_5, mload(_5))
29+
// }
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
{
2+
function userNot(x) -> y {
3+
y := iszero(x)
4+
}
5+
6+
function funcWithLoop(x) {
7+
for {} userNot(x) { mstore(0, 0) } {}
8+
}
9+
10+
mstore(0, 1337)
11+
funcWithLoop(42)
12+
sstore(0, mload(0))
13+
}
14+
// ====
15+
// step: loadResolver
16+
// ----
17+
// {
18+
// function userNot(x) -> y
19+
// { y := iszero(x) }
20+
// function funcWithLoop(x_1)
21+
// {
22+
// for { }
23+
// userNot(x_1)
24+
// {
25+
// let _1 := 0
26+
// mstore(_1, _1)
27+
// }
28+
// { }
29+
// }
30+
// let _3 := 1337
31+
// let _4 := 0
32+
// mstore(_4, _3)
33+
// funcWithLoop(42)
34+
// sstore(_4, mload(_4))
35+
// }
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
function userNot(x) -> y {
3+
y := iszero(x)
4+
}
5+
6+
function funcWithLoop(x) {
7+
for { mstore(0, 0) } userNot(x) {} {}
8+
}
9+
10+
mstore(0, 1337)
11+
funcWithLoop(42)
12+
sstore(0, mload(0))
13+
}
14+
// ====
15+
// step: loadResolver
16+
// ----
17+
// {
18+
// function userNot(x) -> y
19+
// { y := iszero(x) }
20+
// function funcWithLoop(x_1)
21+
// {
22+
// let _1 := 0
23+
// mstore(_1, _1)
24+
// for { } userNot(x_1) { }
25+
// { }
26+
// }
27+
// let _3 := 1337
28+
// let _4 := 0
29+
// mstore(_4, _3)
30+
// funcWithLoop(42)
31+
// sstore(_4, mload(_4))
32+
// }

0 commit comments

Comments
 (0)