Skip to content

Commit efcbc79

Browse files
authored
Merge pull request #13100 from ethereum/fixUnusedStoreInlineAssembly
Fix unused store inline assembly
2 parents 80f6a13 + aa7e4e0 commit efcbc79

File tree

8 files changed

+84
-4
lines changed

8 files changed

+84
-4
lines changed

Changelog.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
### 0.8.15 (unreleased)
22

3+
Important Bugfixes:
4+
* Yul Optimizer: Keep all memory side-effects of inline assembly blocks.
5+
6+
37
Language Features:
48
* Add `E.selector` for a non-anonymous event `E` to access the 32-byte selector topic.
59
* Errors and Events allow qualified access from other contracts.

docs/bugs.json

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
11
[
2+
{
3+
"uid": "SOL-2022-4",
4+
"name": "InlineAssemblyMemorySideEffects",
5+
"summary": "The Yul optimizer may incorrectly remove memory writes from inline assembly blocks, that do not access solidity variables.",
6+
"description": "The Yul optimizer considers all memory writes in the outermost Yul block that are never read from as unused and removes them. This is valid when that Yul block is the entire Yul program, which is always the case for the Yul code generated by the new via-IR pipeline. Inline assembly blocks are never optimized in isolation when using that pipeline. Instead they are optimized as a part of the whole Yul input. However, the legacy code generation pipeline (which is still the default) runs the Yul optimizer individually on an inline assembly block if the block does not refer to any local variables defined in the surrounding Solidity code. Consequently, memory writes in such inline assembly blocks are removed as well, if the written memory is never read from in the same assembly block, even if the written memory is accessed later, for example by a subsequent inline assembly block.",
7+
"link": "https://blog.soliditylang.org/2022/06/15/inline-assembly-memory-side-effects-bug/",
8+
"introduced": "0.8.13",
9+
"fixed": "0.8.15",
10+
"severity": "low/medium",
11+
"conditions": {
12+
"yulOptimizer": true
13+
}
14+
},
215
{
316
"uid": "SOL-2022-3",
417
"name": "DataLocationChangeInInternalOverride",
@@ -8,7 +21,6 @@
821
"introduced": "0.6.9",
922
"fixed": "0.8.14",
1023
"severity": "very low"
11-
1224
},
1325
{
1426
"uid": "SOL-2022-2",

docs/bugs_by_version.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1614,13 +1614,16 @@
16141614
},
16151615
"0.8.13": {
16161616
"bugs": [
1617+
"InlineAssemblyMemorySideEffects",
16171618
"DataLocationChangeInInternalOverride",
16181619
"NestedCallataArrayAbiReencodingSizeValidation"
16191620
],
16201621
"released": "2022-03-16"
16211622
},
16221623
"0.8.14": {
1623-
"bugs": [],
1624+
"bugs": [
1625+
"InlineAssemblyMemorySideEffects"
1626+
],
16241627
"released": "2022-05-17"
16251628
},
16261629
"0.8.2": {

libsolidity/codegen/CompilerContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,7 @@ void CompilerContext::appendInlineAssembly(
485485
obj.code = parserResult;
486486
obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo);
487487

488+
solAssert(!dialect.providesObjectAccess());
488489
optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers);
489490

490491
if (_system)

libyul/optimiser/UnusedStoreEliminator.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
#include <libyul/ControlFlowSideEffectsCollector.h>
3232
#include <libyul/AST.h>
3333

34+
#include <libyul/backends/evm/EVMDialect.h>
35+
3436
#include <libsolutil/CommonData.h>
3537

3638
#include <libevmasm/Instruction.h>
@@ -76,7 +78,13 @@ void UnusedStoreEliminator::run(OptimiserStepContext& _context, Block& _ast)
7678
ignoreMemory
7779
};
7880
rse(_ast);
79-
rse.changeUndecidedTo(State::Unused, Location::Memory);
81+
if (
82+
auto evmDialect = dynamic_cast<EVMDialect const*>(&_context.dialect);
83+
evmDialect && evmDialect->providesObjectAccess()
84+
)
85+
rse.changeUndecidedTo(State::Unused, Location::Memory);
86+
else
87+
rse.changeUndecidedTo(State::Used, Location::Memory);
8088
rse.changeUndecidedTo(State::Used, Location::Storage);
8189
rse.scheduleUnusedForDeletion();
8290

test/libsolidity/semanticTests/array/pop/byte_array_pop_long_storage_empty_garbage_ref.sol

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,5 @@ contract c {
1717
// test() ->
1818
// gas irOptimized: 142639
1919
// gas legacy: 164430
20-
// gas legacyOptimized: 157898
20+
// gas legacyOptimized: 158513
2121
// storageEmpty -> 1
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
contract C {
2+
function f() external returns (uint256 x) {
3+
assembly {
4+
mstore(0, 0x42)
5+
}
6+
assembly {
7+
x := mload(0)
8+
}
9+
}
10+
function g() external returns (bool) {
11+
uint initialFreeMemoryPointer;
12+
assembly {
13+
initialFreeMemoryPointer := mload(0x40)
14+
}
15+
assembly {
16+
let ptr := mload(0x40)
17+
mstore(0x40, add(ptr, 0x20))
18+
}
19+
uint finalFreeMemoryPointer;
20+
assembly {
21+
finalFreeMemoryPointer := mload(0x40)
22+
}
23+
assert(initialFreeMemoryPointer != finalFreeMemoryPointer);
24+
return true;
25+
}
26+
}
27+
// ----
28+
// f() -> 0x42
29+
// g() -> true
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
contract Test {
2+
uint256 x;
3+
4+
function test() public returns (uint256) {
5+
uint256 a = myGetX();
6+
x = 5;
7+
uint256 b = myGetX();
8+
assembly {
9+
log0(0, 64)
10+
}
11+
return a + b + myGetX();
12+
}
13+
14+
function myGetX() internal view returns (uint256) {
15+
assembly {
16+
mstore(1, 0x123456789abcdef)
17+
}
18+
return x;
19+
}
20+
}
21+
// ----
22+
// test() -> 10
23+
// ~ emit <anonymous>: 0x0123456789abcd, 0xef00000000000000000000000000000000000000000000000000000000000000

0 commit comments

Comments
 (0)