1 /*
2 This file is part of solidity.
3
4 solidity is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 3 of the License, or
7 (at your option) any later version.
8
9 solidity is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with solidity. If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 /**
19 * @file SemanticInformation.cpp
20 * @author Christian <c@ethdev.com>
21 * @date 2015
22 * Helper to provide semantic information about assembly items.
23 */
24
25 #include <libevmasm/SemanticInformation.h>
26 #include <libevmasm/AssemblyItem.h>
27
28 using namespace std;
29 using namespace solidity;
30 using namespace solidity::evmasm;
31
breaksCSEAnalysisBlock(AssemblyItem const & _item,bool _msizeImportant)32 bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant)
33 {
34 switch (_item.type())
35 {
36 default:
37 case UndefinedItem:
38 case Tag:
39 case PushDeployTimeAddress:
40 case AssignImmutable:
41 case VerbatimBytecode:
42 return true;
43 case Push:
44 case PushTag:
45 case PushSub:
46 case PushSubSize:
47 case PushProgramSize:
48 case PushData:
49 case PushLibraryAddress:
50 case PushImmutable:
51 return false;
52 case Operation:
53 {
54 if (isSwapInstruction(_item) || isDupInstruction(_item))
55 return false;
56 if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC)
57 return true; // GAS and PC assume a specific order of opcodes
58 if (_item.instruction() == Instruction::MSIZE)
59 return true; // msize is modified already by memory access, avoid that for now
60 InstructionInfo info = instructionInfo(_item.instruction());
61 if (_item.instruction() == Instruction::SSTORE)
62 return false;
63 if (_item.instruction() == Instruction::MSTORE)
64 return false;
65 if (!_msizeImportant && (
66 _item.instruction() == Instruction::MLOAD ||
67 _item.instruction() == Instruction::KECCAK256
68 ))
69 return false;
70 //@todo: We do not handle the following memory instructions for now:
71 // calldatacopy, codecopy, extcodecopy, mstore8,
72 // msize (note that msize also depends on memory read access)
73
74 // the second requirement will be lifted once it is implemented
75 return info.sideEffects || info.args > 2;
76 }
77 }
78 }
79
isCommutativeOperation(AssemblyItem const & _item)80 bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
81 {
82 if (_item.type() != Operation)
83 return false;
84 switch (_item.instruction())
85 {
86 case Instruction::ADD:
87 case Instruction::MUL:
88 case Instruction::EQ:
89 case Instruction::AND:
90 case Instruction::OR:
91 case Instruction::XOR:
92 return true;
93 default:
94 return false;
95 }
96 }
97
isDupInstruction(AssemblyItem const & _item)98 bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
99 {
100 if (_item.type() != Operation)
101 return false;
102 return evmasm::isDupInstruction(_item.instruction());
103 }
104
isSwapInstruction(AssemblyItem const & _item)105 bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
106 {
107 if (_item.type() != Operation)
108 return false;
109 return evmasm::isSwapInstruction(_item.instruction());
110 }
111
isJumpInstruction(AssemblyItem const & _item)112 bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
113 {
114 return _item == Instruction::JUMP || _item == Instruction::JUMPI;
115 }
116
altersControlFlow(AssemblyItem const & _item)117 bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
118 {
119 if (_item.type() != Operation)
120 return false;
121 switch (_item.instruction())
122 {
123 // note that CALL, CALLCODE and CREATE do not really alter the control flow, because we
124 // continue on the next instruction
125 case Instruction::JUMP:
126 case Instruction::JUMPI:
127 case Instruction::RETURN:
128 case Instruction::SELFDESTRUCT:
129 case Instruction::STOP:
130 case Instruction::INVALID:
131 case Instruction::REVERT:
132 return true;
133 default:
134 return false;
135 }
136 }
137
terminatesControlFlow(Instruction _instruction)138 bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
139 {
140 switch (_instruction)
141 {
142 case Instruction::RETURN:
143 case Instruction::SELFDESTRUCT:
144 case Instruction::STOP:
145 case Instruction::INVALID:
146 case Instruction::REVERT:
147 return true;
148 default:
149 return false;
150 }
151 }
152
reverts(Instruction _instruction)153 bool SemanticInformation::reverts(Instruction _instruction)
154 {
155 switch (_instruction)
156 {
157 case Instruction::INVALID:
158 case Instruction::REVERT:
159 return true;
160 default:
161 return false;
162 }
163 }
164
isDeterministic(AssemblyItem const & _item)165 bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
166 {
167 assertThrow(_item.type() != VerbatimBytecode, AssemblyException, "");
168
169 if (_item.type() != Operation)
170 return true;
171
172 switch (_item.instruction())
173 {
174 case Instruction::CALL:
175 case Instruction::CALLCODE:
176 case Instruction::DELEGATECALL:
177 case Instruction::STATICCALL:
178 case Instruction::CREATE:
179 case Instruction::CREATE2:
180 case Instruction::GAS:
181 case Instruction::PC:
182 case Instruction::MSIZE: // depends on previous writes and reads, not only on content
183 case Instruction::BALANCE: // depends on previous calls
184 case Instruction::SELFBALANCE: // depends on previous calls
185 case Instruction::EXTCODESIZE:
186 case Instruction::EXTCODEHASH:
187 case Instruction::RETURNDATACOPY: // depends on previous calls
188 case Instruction::RETURNDATASIZE:
189 return false;
190 default:
191 return true;
192 }
193 }
194
movable(Instruction _instruction)195 bool SemanticInformation::movable(Instruction _instruction)
196 {
197 // These are not really functional.
198 if (isDupInstruction(_instruction) || isSwapInstruction(_instruction))
199 return false;
200 InstructionInfo info = instructionInfo(_instruction);
201 if (info.sideEffects)
202 return false;
203 switch (_instruction)
204 {
205 case Instruction::KECCAK256:
206 case Instruction::BALANCE:
207 case Instruction::SELFBALANCE:
208 case Instruction::EXTCODESIZE:
209 case Instruction::EXTCODEHASH:
210 case Instruction::RETURNDATASIZE:
211 case Instruction::SLOAD:
212 case Instruction::PC:
213 case Instruction::MSIZE:
214 case Instruction::GAS:
215 return false;
216 default:
217 return true;
218 }
219 return true;
220 }
221
canBeRemoved(Instruction _instruction)222 bool SemanticInformation::canBeRemoved(Instruction _instruction)
223 {
224 // These are not really functional.
225 assertThrow(!isDupInstruction(_instruction) && !isSwapInstruction(_instruction), AssemblyException, "");
226
227 return !instructionInfo(_instruction).sideEffects;
228 }
229
canBeRemovedIfNoMSize(Instruction _instruction)230 bool SemanticInformation::canBeRemovedIfNoMSize(Instruction _instruction)
231 {
232 if (_instruction == Instruction::KECCAK256 || _instruction == Instruction::MLOAD)
233 return true;
234 else
235 return canBeRemoved(_instruction);
236 }
237
memory(Instruction _instruction)238 SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction)
239 {
240 switch (_instruction)
241 {
242 case Instruction::CALLDATACOPY:
243 case Instruction::CODECOPY:
244 case Instruction::EXTCODECOPY:
245 case Instruction::RETURNDATACOPY:
246 case Instruction::MSTORE:
247 case Instruction::MSTORE8:
248 case Instruction::CALL:
249 case Instruction::CALLCODE:
250 case Instruction::DELEGATECALL:
251 case Instruction::STATICCALL:
252 return SemanticInformation::Write;
253
254 case Instruction::CREATE:
255 case Instruction::CREATE2:
256 case Instruction::KECCAK256:
257 case Instruction::MLOAD:
258 case Instruction::MSIZE:
259 case Instruction::RETURN:
260 case Instruction::REVERT:
261 case Instruction::LOG0:
262 case Instruction::LOG1:
263 case Instruction::LOG2:
264 case Instruction::LOG3:
265 case Instruction::LOG4:
266 return SemanticInformation::Read;
267
268 default:
269 return SemanticInformation::None;
270 }
271 }
272
movableApartFromEffects(Instruction _instruction)273 bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
274 {
275 switch (_instruction)
276 {
277 case Instruction::EXTCODEHASH:
278 case Instruction::EXTCODESIZE:
279 case Instruction::RETURNDATASIZE:
280 case Instruction::BALANCE:
281 case Instruction::SELFBALANCE:
282 case Instruction::SLOAD:
283 case Instruction::KECCAK256:
284 case Instruction::MLOAD:
285 return true;
286
287 default:
288 return movable(_instruction);
289 }
290 }
291
storage(Instruction _instruction)292 SemanticInformation::Effect SemanticInformation::storage(Instruction _instruction)
293 {
294 switch (_instruction)
295 {
296 case Instruction::CALL:
297 case Instruction::CALLCODE:
298 case Instruction::DELEGATECALL:
299 case Instruction::CREATE:
300 case Instruction::CREATE2:
301 case Instruction::SSTORE:
302 return SemanticInformation::Write;
303
304 case Instruction::SLOAD:
305 case Instruction::STATICCALL:
306 return SemanticInformation::Read;
307
308 default:
309 return SemanticInformation::None;
310 }
311 }
312
otherState(Instruction _instruction)313 SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruction)
314 {
315 switch (_instruction)
316 {
317 case Instruction::CALL:
318 case Instruction::CALLCODE:
319 case Instruction::DELEGATECALL:
320 case Instruction::CREATE:
321 case Instruction::CREATE2:
322 case Instruction::SELFDESTRUCT:
323 case Instruction::STATICCALL: // because it can affect returndatasize
324 // Strictly speaking, log0, .., log4 writes to the state, but the EVM cannot read it, so they
325 // are just marked as having 'other side effects.'
326 return SemanticInformation::Write;
327
328 case Instruction::EXTCODESIZE:
329 case Instruction::EXTCODEHASH:
330 case Instruction::RETURNDATASIZE:
331 case Instruction::BALANCE:
332 case Instruction::SELFBALANCE:
333 case Instruction::RETURNDATACOPY:
334 case Instruction::EXTCODECOPY:
335 // PC and GAS are specifically excluded here. Instructions such as CALLER, CALLVALUE,
336 // ADDRESS are excluded because they cannot change during execution.
337 return SemanticInformation::Read;
338
339 default:
340 return SemanticInformation::None;
341 }
342 }
343
invalidInPureFunctions(Instruction _instruction)344 bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
345 {
346 switch (_instruction)
347 {
348 case Instruction::ADDRESS:
349 case Instruction::SELFBALANCE:
350 case Instruction::BALANCE:
351 case Instruction::ORIGIN:
352 case Instruction::CALLER:
353 case Instruction::CALLVALUE:
354 case Instruction::CHAINID:
355 case Instruction::BASEFEE:
356 case Instruction::GAS:
357 case Instruction::GASPRICE:
358 case Instruction::EXTCODESIZE:
359 case Instruction::EXTCODECOPY:
360 case Instruction::EXTCODEHASH:
361 case Instruction::BLOCKHASH:
362 case Instruction::COINBASE:
363 case Instruction::TIMESTAMP:
364 case Instruction::NUMBER:
365 case Instruction::DIFFICULTY:
366 case Instruction::GASLIMIT:
367 case Instruction::STATICCALL:
368 case Instruction::SLOAD:
369 return true;
370 default:
371 break;
372 }
373 return invalidInViewFunctions(_instruction);
374 }
375
invalidInViewFunctions(Instruction _instruction)376 bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
377 {
378 switch (_instruction)
379 {
380 case Instruction::SSTORE:
381 case Instruction::JUMP:
382 case Instruction::JUMPI:
383 case Instruction::LOG0:
384 case Instruction::LOG1:
385 case Instruction::LOG2:
386 case Instruction::LOG3:
387 case Instruction::LOG4:
388 case Instruction::CREATE:
389 case Instruction::CALL:
390 case Instruction::CALLCODE:
391 case Instruction::DELEGATECALL:
392 case Instruction::CREATE2:
393 case Instruction::SELFDESTRUCT:
394 return true;
395 default:
396 break;
397 }
398 return false;
399 }
400