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