Coverage Report

Created: 2022-08-24 06:31

/src/solidity/libevmasm/SemanticInformation.cpp
Line
Count
Source (jump to first uncovered line)
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
32
vector<SemanticInformation::Operation> SemanticInformation::readWriteOperations(Instruction _instruction)
33
0
{
34
0
  switch (_instruction)
35
0
  {
36
0
  case Instruction::SSTORE:
37
0
  case Instruction::SLOAD:
38
0
  {
39
0
    assertThrow(memory(_instruction) == Effect::None, OptimizerException, "");
40
0
    assertThrow(storage(_instruction) != Effect::None, OptimizerException, "");
41
0
    Operation op;
42
0
    op.effect = storage(_instruction);
43
0
    op.location = Location::Storage;
44
0
    op.startParameter = 0;
45
    // We know that exactly one slot is affected.
46
0
    op.lengthConstant = 1;
47
0
    return {op};
48
0
  }
49
0
  case Instruction::MSTORE:
50
0
  case Instruction::MSTORE8:
51
0
  case Instruction::MLOAD:
52
0
  {
53
0
    assertThrow(memory(_instruction) != Effect::None, OptimizerException, "");
54
0
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
55
0
    Operation op;
56
0
    op.effect = memory(_instruction);
57
0
    op.location = Location::Memory;
58
0
    op.startParameter = 0;
59
0
    if (_instruction == Instruction::MSTORE || _instruction == Instruction::MLOAD)
60
0
      op.lengthConstant = 32;
61
0
    else if (_instruction == Instruction::MSTORE8)
62
0
      op.lengthConstant = 1;
63
64
0
    return {op};
65
0
  }
66
0
  case Instruction::REVERT:
67
0
  case Instruction::RETURN:
68
0
  case Instruction::KECCAK256:
69
0
  case Instruction::LOG0:
70
0
  case Instruction::LOG1:
71
0
  case Instruction::LOG2:
72
0
  case Instruction::LOG3:
73
0
  case Instruction::LOG4:
74
0
  {
75
0
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
76
0
    assertThrow(memory(_instruction) == Effect::Read, OptimizerException, "");
77
0
    Operation op;
78
0
    op.effect = memory(_instruction);
79
0
    op.location = Location::Memory;
80
0
    op.startParameter = 0;
81
0
    op.lengthParameter = 1;
82
0
    return {op};
83
0
  }
84
0
  case Instruction::EXTCODECOPY:
85
0
  {
86
0
    assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
87
0
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
88
0
    Operation op;
89
0
    op.effect = memory(_instruction);
90
0
    op.location = Location::Memory;
91
0
    op.startParameter = 1;
92
0
    op.lengthParameter = 3;
93
0
    return {op};
94
0
  }
95
0
  case Instruction::CODECOPY:
96
0
  case Instruction::CALLDATACOPY:
97
0
  case Instruction::RETURNDATACOPY:
98
0
  {
99
0
    assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
100
0
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
101
0
    Operation op;
102
0
    op.effect = memory(_instruction);
103
0
    op.location = Location::Memory;
104
0
    op.startParameter = 0;
105
0
    op.lengthParameter = 2;
106
0
    return {op};
107
0
  }
108
0
  case Instruction::STATICCALL:
109
0
  case Instruction::CALL:
110
0
  case Instruction::CALLCODE:
111
0
  case Instruction::DELEGATECALL:
112
0
  {
113
0
    size_t paramCount = static_cast<size_t>(instructionInfo(_instruction).args);
114
0
    vector<Operation> operations{
115
0
      Operation{Location::Memory, Effect::Read, paramCount - 4, paramCount - 3, {}},
116
0
      Operation{Location::Storage, Effect::Read, {}, {}, {}}
117
0
    };
118
0
    if (_instruction != Instruction::STATICCALL)
119
0
      operations.emplace_back(Operation{Location::Storage, Effect::Write, {}, {}, {}});
120
0
    operations.emplace_back(Operation{
121
0
      Location::Memory,
122
0
      Effect::Write,
123
0
      paramCount - 2,
124
      // Length is in paramCount - 1, but it is only a max length,
125
      // there is no guarantee that the full area is written to.
126
0
      {},
127
0
      {}
128
0
    });
129
0
    return operations;
130
0
  }
131
0
  case Instruction::CREATE:
132
0
  case Instruction::CREATE2:
133
0
    return vector<Operation>{
134
0
      Operation{
135
0
        Location::Memory,
136
0
        Effect::Read,
137
0
        1,
138
0
        2,
139
0
        {}
140
0
      },
141
0
      Operation{Location::Storage, Effect::Read, {}, {}, {}},
142
0
      Operation{Location::Storage, Effect::Write, {}, {}, {}}
143
0
    };
144
0
  case Instruction::MSIZE:
145
    // This is just to satisfy the assert below.
146
0
    return vector<Operation>{};
147
0
  default:
148
0
    assertThrow(storage(_instruction) == None && memory(_instruction) == None, AssemblyException, "");
149
0
  }
150
0
  return {};
151
0
}
152
153
bool SemanticInformation::breaksCSEAnalysisBlock(AssemblyItem const& _item, bool _msizeImportant)
154
0
{
155
0
  switch (_item.type())
156
0
  {
157
0
  default:
158
0
  case UndefinedItem:
159
0
  case Tag:
160
0
  case PushDeployTimeAddress:
161
0
  case AssignImmutable:
162
0
  case VerbatimBytecode:
163
0
    return true;
164
0
  case Push:
165
0
  case PushTag:
166
0
  case PushSub:
167
0
  case PushSubSize:
168
0
  case PushProgramSize:
169
0
  case PushData:
170
0
  case PushLibraryAddress:
171
0
  case PushImmutable:
172
0
    return false;
173
0
  case evmasm::Operation:
174
0
  {
175
0
    if (isSwapInstruction(_item) || isDupInstruction(_item))
176
0
      return false;
177
0
    if (_item.instruction() == Instruction::GAS || _item.instruction() == Instruction::PC)
178
0
      return true; // GAS and PC assume a specific order of opcodes
179
0
    if (_item.instruction() == Instruction::MSIZE)
180
0
      return true; // msize is modified already by memory access, avoid that for now
181
0
    InstructionInfo info = instructionInfo(_item.instruction());
182
0
    if (_item.instruction() == Instruction::SSTORE)
183
0
      return false;
184
0
    if (_item.instruction() == Instruction::MSTORE)
185
0
      return false;
186
0
    if (!_msizeImportant && (
187
0
      _item.instruction() == Instruction::MLOAD ||
188
0
      _item.instruction() == Instruction::KECCAK256
189
0
    ))
190
0
      return false;
191
    //@todo: We do not handle the following memory instructions for now:
192
    // calldatacopy, codecopy, extcodecopy, mstore8,
193
    // msize (note that msize also depends on memory read access)
194
195
    // the second requirement will be lifted once it is implemented
196
0
    return info.sideEffects || info.args > 2;
197
0
  }
198
0
  }
199
0
}
200
201
bool SemanticInformation::isCommutativeOperation(AssemblyItem const& _item)
202
0
{
203
0
  if (_item.type() != evmasm::Operation)
204
0
    return false;
205
0
  switch (_item.instruction())
206
0
  {
207
0
  case Instruction::ADD:
208
0
  case Instruction::MUL:
209
0
  case Instruction::EQ:
210
0
  case Instruction::AND:
211
0
  case Instruction::OR:
212
0
  case Instruction::XOR:
213
0
    return true;
214
0
  default:
215
0
    return false;
216
0
  }
217
0
}
218
219
bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
220
0
{
221
0
  if (_item.type() != evmasm::Operation)
222
0
    return false;
223
0
  return evmasm::isDupInstruction(_item.instruction());
224
0
}
225
226
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
227
0
{
228
0
  if (_item.type() != evmasm::Operation)
229
0
    return false;
230
0
  return evmasm::isSwapInstruction(_item.instruction());
231
0
}
232
233
bool SemanticInformation::isJumpInstruction(AssemblyItem const& _item)
234
0
{
235
0
  return _item == Instruction::JUMP || _item == Instruction::JUMPI;
236
0
}
237
238
bool SemanticInformation::altersControlFlow(AssemblyItem const& _item)
239
0
{
240
0
  if (_item.type() != evmasm::Operation)
241
0
    return false;
242
0
  switch (_item.instruction())
243
0
  {
244
  // note that CALL, CALLCODE and CREATE do not really alter the control flow, because we
245
  // continue on the next instruction
246
0
  case Instruction::JUMP:
247
0
  case Instruction::JUMPI:
248
0
  case Instruction::RETURN:
249
0
  case Instruction::SELFDESTRUCT:
250
0
  case Instruction::STOP:
251
0
  case Instruction::INVALID:
252
0
  case Instruction::REVERT:
253
0
    return true;
254
0
  default:
255
0
    return false;
256
0
  }
257
0
}
258
259
bool SemanticInformation::terminatesControlFlow(Instruction _instruction)
260
0
{
261
0
  switch (_instruction)
262
0
  {
263
0
  case Instruction::RETURN:
264
0
  case Instruction::SELFDESTRUCT:
265
0
  case Instruction::STOP:
266
0
  case Instruction::INVALID:
267
0
  case Instruction::REVERT:
268
0
    return true;
269
0
  default:
270
0
    return false;
271
0
  }
272
0
}
273
274
bool SemanticInformation::reverts(Instruction _instruction)
275
0
{
276
0
  switch (_instruction)
277
0
  {
278
0
    case Instruction::INVALID:
279
0
    case Instruction::REVERT:
280
0
      return true;
281
0
    default:
282
0
      return false;
283
0
  }
284
0
}
285
286
bool SemanticInformation::isDeterministic(AssemblyItem const& _item)
287
0
{
288
0
  assertThrow(_item.type() != VerbatimBytecode, AssemblyException, "");
289
290
0
  if (_item.type() != evmasm::Operation)
291
0
    return true;
292
293
0
  switch (_item.instruction())
294
0
  {
295
0
  case Instruction::CALL:
296
0
  case Instruction::CALLCODE:
297
0
  case Instruction::DELEGATECALL:
298
0
  case Instruction::STATICCALL:
299
0
  case Instruction::CREATE:
300
0
  case Instruction::CREATE2:
301
0
  case Instruction::GAS:
302
0
  case Instruction::PC:
303
0
  case Instruction::MSIZE: // depends on previous writes and reads, not only on content
304
0
  case Instruction::BALANCE: // depends on previous calls
305
0
  case Instruction::SELFBALANCE: // depends on previous calls
306
0
  case Instruction::EXTCODESIZE:
307
0
  case Instruction::EXTCODEHASH:
308
0
  case Instruction::RETURNDATACOPY: // depends on previous calls
309
0
  case Instruction::RETURNDATASIZE:
310
0
    return false;
311
0
  default:
312
0
    return true;
313
0
  }
314
0
}
315
316
bool SemanticInformation::movable(Instruction _instruction)
317
0
{
318
  // These are not really functional.
319
0
  if (isDupInstruction(_instruction) || isSwapInstruction(_instruction))
320
0
    return false;
321
0
  InstructionInfo info = instructionInfo(_instruction);
322
0
  if (info.sideEffects)
323
0
    return false;
324
0
  switch (_instruction)
325
0
  {
326
0
  case Instruction::KECCAK256:
327
0
  case Instruction::BALANCE:
328
0
  case Instruction::SELFBALANCE:
329
0
  case Instruction::EXTCODESIZE:
330
0
  case Instruction::EXTCODEHASH:
331
0
  case Instruction::RETURNDATASIZE:
332
0
  case Instruction::SLOAD:
333
0
  case Instruction::PC:
334
0
  case Instruction::MSIZE:
335
0
  case Instruction::GAS:
336
0
    return false;
337
0
  default:
338
0
    return true;
339
0
  }
340
0
  return true;
341
0
}
342
343
bool SemanticInformation::canBeRemoved(Instruction _instruction)
344
0
{
345
  // These are not really functional.
346
0
  assertThrow(!isDupInstruction(_instruction) && !isSwapInstruction(_instruction), AssemblyException, "");
347
348
0
  return !instructionInfo(_instruction).sideEffects;
349
0
}
350
351
bool SemanticInformation::canBeRemovedIfNoMSize(Instruction _instruction)
352
0
{
353
0
  if (_instruction == Instruction::KECCAK256 || _instruction == Instruction::MLOAD)
354
0
    return true;
355
0
  else
356
0
    return canBeRemoved(_instruction);
357
0
}
358
359
SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction)
360
0
{
361
0
  switch (_instruction)
362
0
  {
363
0
  case Instruction::CALLDATACOPY:
364
0
  case Instruction::CODECOPY:
365
0
  case Instruction::EXTCODECOPY:
366
0
  case Instruction::RETURNDATACOPY:
367
0
  case Instruction::MSTORE:
368
0
  case Instruction::MSTORE8:
369
0
  case Instruction::CALL:
370
0
  case Instruction::CALLCODE:
371
0
  case Instruction::DELEGATECALL:
372
0
  case Instruction::STATICCALL:
373
0
    return SemanticInformation::Write;
374
375
0
  case Instruction::CREATE:
376
0
  case Instruction::CREATE2:
377
0
  case Instruction::KECCAK256:
378
0
  case Instruction::MLOAD:
379
0
  case Instruction::MSIZE:
380
0
  case Instruction::RETURN:
381
0
  case Instruction::REVERT:
382
0
  case Instruction::LOG0:
383
0
  case Instruction::LOG1:
384
0
  case Instruction::LOG2:
385
0
  case Instruction::LOG3:
386
0
  case Instruction::LOG4:
387
0
    return SemanticInformation::Read;
388
389
0
  default:
390
0
    return SemanticInformation::None;
391
0
  }
392
0
}
393
394
bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
395
0
{
396
0
  switch (_instruction)
397
0
  {
398
0
  case Instruction::EXTCODEHASH:
399
0
  case Instruction::EXTCODESIZE:
400
0
  case Instruction::RETURNDATASIZE:
401
0
  case Instruction::BALANCE:
402
0
  case Instruction::SELFBALANCE:
403
0
  case Instruction::SLOAD:
404
0
  case Instruction::KECCAK256:
405
0
  case Instruction::MLOAD:
406
0
    return true;
407
408
0
  default:
409
0
    return movable(_instruction);
410
0
  }
411
0
}
412
413
SemanticInformation::Effect SemanticInformation::storage(Instruction _instruction)
414
0
{
415
0
  switch (_instruction)
416
0
  {
417
0
  case Instruction::CALL:
418
0
  case Instruction::CALLCODE:
419
0
  case Instruction::DELEGATECALL:
420
0
  case Instruction::CREATE:
421
0
  case Instruction::CREATE2:
422
0
  case Instruction::SSTORE:
423
0
    return SemanticInformation::Write;
424
425
0
  case Instruction::SLOAD:
426
0
  case Instruction::STATICCALL:
427
0
    return SemanticInformation::Read;
428
429
0
  default:
430
0
    return SemanticInformation::None;
431
0
  }
432
0
}
433
434
SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruction)
435
0
{
436
0
  switch (_instruction)
437
0
  {
438
0
  case Instruction::CALL:
439
0
  case Instruction::CALLCODE:
440
0
  case Instruction::DELEGATECALL:
441
0
  case Instruction::CREATE:
442
0
  case Instruction::CREATE2:
443
0
  case Instruction::SELFDESTRUCT:
444
0
  case Instruction::STATICCALL: // because it can affect returndatasize
445
    // Strictly speaking, log0, .., log4 writes to the state, but the EVM cannot read it, so they
446
    // are just marked as having 'other side effects.'
447
0
    return SemanticInformation::Write;
448
449
0
  case Instruction::EXTCODESIZE:
450
0
  case Instruction::EXTCODEHASH:
451
0
  case Instruction::RETURNDATASIZE:
452
0
  case Instruction::BALANCE:
453
0
  case Instruction::SELFBALANCE:
454
0
  case Instruction::RETURNDATACOPY:
455
0
  case Instruction::EXTCODECOPY:
456
    // PC and GAS are specifically excluded here. Instructions such as CALLER, CALLVALUE,
457
    // ADDRESS are excluded because they cannot change during execution.
458
0
    return SemanticInformation::Read;
459
460
0
  default:
461
0
    return SemanticInformation::None;
462
0
  }
463
0
}
464
465
bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
466
0
{
467
0
  switch (_instruction)
468
0
  {
469
0
  case Instruction::ADDRESS:
470
0
  case Instruction::SELFBALANCE:
471
0
  case Instruction::BALANCE:
472
0
  case Instruction::ORIGIN:
473
0
  case Instruction::CALLER:
474
0
  case Instruction::CALLVALUE:
475
0
  case Instruction::CHAINID:
476
0
  case Instruction::BASEFEE:
477
0
  case Instruction::GAS:
478
0
  case Instruction::GASPRICE:
479
0
  case Instruction::EXTCODESIZE:
480
0
  case Instruction::EXTCODECOPY:
481
0
  case Instruction::EXTCODEHASH:
482
0
  case Instruction::BLOCKHASH:
483
0
  case Instruction::COINBASE:
484
0
  case Instruction::TIMESTAMP:
485
0
  case Instruction::NUMBER:
486
0
  case Instruction::DIFFICULTY:
487
0
  case Instruction::GASLIMIT:
488
0
  case Instruction::STATICCALL:
489
0
  case Instruction::SLOAD:
490
0
    return true;
491
0
  default:
492
0
    break;
493
0
  }
494
0
  return invalidInViewFunctions(_instruction);
495
0
}
496
497
bool SemanticInformation::invalidInViewFunctions(Instruction _instruction)
498
0
{
499
0
  switch (_instruction)
500
0
  {
501
0
  case Instruction::SSTORE:
502
0
  case Instruction::JUMP:
503
0
  case Instruction::JUMPI:
504
0
  case Instruction::LOG0:
505
0
  case Instruction::LOG1:
506
0
  case Instruction::LOG2:
507
0
  case Instruction::LOG3:
508
0
  case Instruction::LOG4:
509
0
  case Instruction::CREATE:
510
0
  case Instruction::CALL:
511
0
  case Instruction::CALLCODE:
512
0
  case Instruction::DELEGATECALL:
513
0
  case Instruction::CREATE2:
514
0
  case Instruction::SELFDESTRUCT:
515
0
    return true;
516
0
  default:
517
0
    break;
518
0
  }
519
0
  return false;
520
0
}