Skip to content

Commit 9d90b39

Browse files
authored
Merge pull request #15262 from ethereum/subObjectNonDeterminism
Order yul subobjects by order of reference.
2 parents 5565b86 + c78b7e2 commit 9d90b39

File tree

7 files changed

+118
-6
lines changed

7 files changed

+118
-6
lines changed

Changelog.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ Bugfixes:
1919
* SMTChecker: Fix formatting of unary minus expressions in invariants.
2020
* SMTChecker: Fix internal compiler error when reporting proved targets for BMC engine.
2121
* TypeChecker: Fix segfault when assigning nested tuple to tuple.
22+
* Yul IR Code Generation: Deterministic order of Yul subobjects.
2223
* Yul Optimizer: Name simplification could lead to forbidden identifiers with a leading and/or trailing dot, e.g., ``x._`` would get simplified into ``x.``.
2324
* Yul Parser: Fix segfault when parsing very long location comments.
2425

libsolidity/codegen/ir/IRGenerationContext.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,8 @@ class IRGenerationContext
143143

144144
RevertStrings revertStrings() const { return m_revertStrings; }
145145

146-
std::set<ContractDefinition const*, ASTNode::CompareByID>& subObjectsCreated() { return m_subObjects; }
146+
util::UniqueVector<ContractDefinition const*> const& subObjectsCreated() const { return m_subObjects; }
147+
void addSubObject(ContractDefinition const* _contractDefinition) { m_subObjects.pushBack(_contractDefinition); }
147148

148149
bool memoryUnsafeInlineAssemblySeen() const { return m_memoryUnsafeInlineAssemblySeen; }
149150
void setMemoryUnsafeInlineAssemblySeen() { m_memoryUnsafeInlineAssemblySeen = true; }
@@ -195,7 +196,7 @@ class IRGenerationContext
195196
/// It will fail at runtime but the code must still compile.
196197
InternalDispatchMap m_internalDispatchMap;
197198

198-
std::set<ContractDefinition const*, ASTNode::CompareByID> m_subObjects;
199+
util::UniqueVector<ContractDefinition const*> m_subObjects;
199200

200201
langutil::DebugInfoSelection m_debugInfoSelection = {};
201202
langutil::CharStreamProvider const* m_soliditySourceProvider = nullptr;

libsolidity/codegen/ir/IRGenerator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,10 +101,10 @@ std::string IRGenerator::generate(
101101
std::map<ContractDefinition const*, std::string_view const> const& _otherYulSources
102102
)
103103
{
104-
auto subObjectSources = [&_otherYulSources](std::set<ContractDefinition const*, ASTNode::CompareByID> const& subObjects) -> std::string
104+
auto subObjectSources = [&_otherYulSources](UniqueVector<ContractDefinition const*> const& _subObjects) -> std::string
105105
{
106106
std::string subObjectsSources;
107-
for (ContractDefinition const* subObject: subObjects)
107+
for (ContractDefinition const* subObject: _subObjects)
108108
subObjectsSources += _otherYulSources.at(subObject);
109109
return subObjectsSources;
110110
};

libsolidity/codegen/ir/IRGeneratorForStatements.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1559,7 +1559,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
15591559

15601560
ContractDefinition const* contract =
15611561
&dynamic_cast<ContractType const&>(*functionType->returnParameterTypes().front()).contractDefinition();
1562-
m_context.subObjectsCreated().insert(contract);
1562+
m_context.addSubObject(contract);
15631563

15641564
Whiskers t(R"(let <memPos> := <allocateUnbounded>()
15651565
let <memEnd> := add(<memPos>, datasize("<object>"))
@@ -1947,7 +1947,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
19471947
auto const& contractType = dynamic_cast<ContractType const&>(*arg);
19481948
solAssert(!contractType.isSuper());
19491949
ContractDefinition const& contract = contractType.contractDefinition();
1950-
m_context.subObjectsCreated().insert(&contract);
1950+
m_context.addSubObject(&contract);
19511951
appendCode() << Whiskers(R"(
19521952
let <size> := datasize("<objectName>")
19531953
let <result> := <allocationFunction>(add(<size>, 32))
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--ir-optimized --optimize --debug-info none
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// SPDX-License-Identifier: GPL-3.0
2+
pragma solidity >0.0.0;
3+
4+
contract B { constructor() payable { assembly { revert(0,0) } } }
5+
contract A { constructor() payable { assembly { revert(0,0) } } }
6+
contract C {
7+
// The subobject order should be determined by reference, not AST ID,
8+
// So the subobject for A should precede the subobject for B.
9+
A a = new A();
10+
B b = new B();
11+
fallback() external payable {
12+
assembly { revert(0,0) }
13+
}
14+
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
Optimized IR:
2+
/// @use-src 0:"ir_subobject_order/input.sol"
3+
object "A_13" {
4+
code { { revert(0, 0) } }
5+
/// @use-src 0:"ir_subobject_order/input.sol"
6+
object "A_13_deployed" {
7+
code { { revert(0, 0) } }
8+
data ".metadata" hex"<BYTECODE REMOVED>"
9+
}
10+
}
11+
12+
Optimized IR:
13+
/// @use-src 0:"ir_subobject_order/input.sol"
14+
object "B_7" {
15+
code { { revert(0, 0) } }
16+
/// @use-src 0:"ir_subobject_order/input.sol"
17+
object "B_7_deployed" {
18+
code { { revert(0, 0) } }
19+
data ".metadata" hex"<BYTECODE REMOVED>"
20+
}
21+
}
22+
23+
Optimized IR:
24+
/// @use-src 0:"ir_subobject_order/input.sol"
25+
object "C_33" {
26+
code {
27+
{
28+
let _1 := memoryguard(0x80)
29+
mstore(64, _1)
30+
if callvalue() { revert(0, 0) }
31+
let _2 := datasize("A_13")
32+
let _3 := add(_1, _2)
33+
if or(gt(_3, sub(shl(64, 1), 1)), lt(_3, _1))
34+
{
35+
mstore(0, shl(224, 0x4e487b71))
36+
mstore(4, 0x41)
37+
revert(0, 0x24)
38+
}
39+
datacopy(_1, dataoffset("A_13"), _2)
40+
let expr_address := create(0, _1, sub(_3, _1))
41+
if iszero(expr_address)
42+
{
43+
let pos := mload(64)
44+
returndatacopy(pos, 0, returndatasize())
45+
revert(pos, returndatasize())
46+
}
47+
sstore(0, or(and(sload(0), not(sub(shl(160, 1), 1))), and(expr_address, sub(shl(160, 1), 1))))
48+
let _4 := mload(64)
49+
let _5 := datasize("B_7")
50+
let _6 := add(_4, _5)
51+
if or(gt(_6, sub(shl(64, 1), 1)), lt(_6, _4))
52+
{
53+
mstore(0, shl(224, 0x4e487b71))
54+
mstore(4, 0x41)
55+
revert(0, 0x24)
56+
}
57+
datacopy(_4, dataoffset("B_7"), _5)
58+
let expr_address_1 := create(0, _4, sub(_6, _4))
59+
if iszero(expr_address_1)
60+
{
61+
let pos_1 := mload(64)
62+
returndatacopy(pos_1, 0, returndatasize())
63+
revert(pos_1, returndatasize())
64+
}
65+
sstore(0x01, or(and(sload(0x01), not(sub(shl(160, 1), 1))), and(expr_address_1, sub(shl(160, 1), 1))))
66+
let _7 := mload(64)
67+
let _8 := datasize("C_33_deployed")
68+
codecopy(_7, dataoffset("C_33_deployed"), _8)
69+
return(_7, _8)
70+
}
71+
}
72+
/// @use-src 0:"ir_subobject_order/input.sol"
73+
object "C_33_deployed" {
74+
code { { revert(0, 0) } }
75+
data ".metadata" hex"<BYTECODE REMOVED>"
76+
}
77+
/// @use-src 0:"ir_subobject_order/input.sol"
78+
object "A_13" {
79+
code { { revert(0, 0) } }
80+
/// @use-src 0:"ir_subobject_order/input.sol"
81+
object "A_13_deployed" {
82+
code { { revert(0, 0) } }
83+
data ".metadata" hex"<BYTECODE REMOVED>"
84+
}
85+
}
86+
/// @use-src 0:"ir_subobject_order/input.sol"
87+
object "B_7" {
88+
code { { revert(0, 0) } }
89+
/// @use-src 0:"ir_subobject_order/input.sol"
90+
object "B_7_deployed" {
91+
code { { revert(0, 0) } }
92+
data ".metadata" hex"<BYTECODE REMOVED>"
93+
}
94+
}
95+
}

0 commit comments

Comments
 (0)