Coverage Report

Created: 2022-08-24 06:38

/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
2.79M
{
34
2.79M
  switch (_instruction)
35
2.79M
  {
36
424k
  case Instruction::SSTORE:
37
500k
  case Instruction::SLOAD:
38
500k
  {
39
500k
    assertThrow(memory(_instruction) == Effect::None, OptimizerException, "");
40
500k
    assertThrow(storage(_instruction) != Effect::None, OptimizerException, "");
41
500k
    Operation op;
42
500k
    op.effect = storage(_instruction);
43
500k
    op.location = Location::Storage;
44
500k
    op.startParameter = 0;
45
    // We know that exactly one slot is affected.
46
500k
    op.lengthConstant = 1;
47
500k
    return {op};
48
500k
  }
49
208k
  case Instruction::MSTORE:
50
218k
  case Instruction::MSTORE8:
51
333k
  case Instruction::MLOAD:
52
333k
  {
53
333k
    assertThrow(memory(_instruction) != Effect::None, OptimizerException, "");
54
333k
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
55
333k
    Operation op;
56
333k
    op.effect = memory(_instruction);
57
333k
    op.location = Location::Memory;
58
333k
    op.startParameter = 0;
59
333k
    if (_instruction == Instruction::MSTORE || _instruction == Instruction::MLOAD)
60
323k
      op.lengthConstant = 32;
61
9.86k
    else if (_instruction == Instruction::MSTORE8)
62
9.86k
      op.lengthConstant = 1;
63
64
333k
    return {op};
65
333k
  }
66
1.18k
  case Instruction::REVERT:
67
3.74k
  case Instruction::RETURN:
68
23.8k
  case Instruction::KECCAK256:
69
35.5k
  case Instruction::LOG0:
70
39.0k
  case Instruction::LOG1:
71
43.0k
  case Instruction::LOG2:
72
45.9k
  case Instruction::LOG3:
73
71.3k
  case Instruction::LOG4:
74
71.3k
  {
75
71.3k
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
76
71.3k
    assertThrow(memory(_instruction) == Effect::Read, OptimizerException, "");
77
71.3k
    Operation op;
78
71.3k
    op.effect = memory(_instruction);
79
71.3k
    op.location = Location::Memory;
80
71.3k
    op.startParameter = 0;
81
71.3k
    op.lengthParameter = 1;
82
71.3k
    return {op};
83
71.3k
  }
84
33.9k
  case Instruction::EXTCODECOPY:
85
33.9k
  {
86
33.9k
    assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
87
33.9k
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
88
33.9k
    Operation op;
89
33.9k
    op.effect = memory(_instruction);
90
33.9k
    op.location = Location::Memory;
91
33.9k
    op.startParameter = 1;
92
33.9k
    op.lengthParameter = 3;
93
33.9k
    return {op};
94
33.9k
  }
95
18.2k
  case Instruction::CODECOPY:
96
42.8k
  case Instruction::CALLDATACOPY:
97
71.2k
  case Instruction::RETURNDATACOPY:
98
71.2k
  {
99
71.2k
    assertThrow(memory(_instruction) == Effect::Write, OptimizerException, "");
100
71.2k
    assertThrow(storage(_instruction) == Effect::None, OptimizerException, "");
101
71.2k
    Operation op;
102
71.2k
    op.effect = memory(_instruction);
103
71.2k
    op.location = Location::Memory;
104
71.2k
    op.startParameter = 0;
105
71.2k
    op.lengthParameter = 2;
106
71.2k
    return {op};
107
71.2k
  }
108
173k
  case Instruction::STATICCALL:
109
297k
  case Instruction::CALL:
110
356k
  case Instruction::CALLCODE:
111
379k
  case Instruction::DELEGATECALL:
112
379k
  {
113
379k
    size_t paramCount = static_cast<size_t>(instructionInfo(_instruction).args);
114
379k
    vector<Operation> operations{
115
379k
      Operation{Location::Memory, Effect::Read, paramCount - 4, paramCount - 3, {}},
116
379k
      Operation{Location::Storage, Effect::Read, {}, {}, {}}
117
379k
    };
118
379k
    if (_instruction != Instruction::STATICCALL)
119
205k
      operations.emplace_back(Operation{Location::Storage, Effect::Write, {}, {}, {}});
120
379k
    operations.emplace_back(Operation{
121
379k
      Location::Memory,
122
379k
      Effect::Write,
123
379k
      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
379k
      {},
127
379k
      {}
128
379k
    });
129
379k
    return operations;
130
356k
  }
131
57.6k
  case Instruction::CREATE:
132
76.1k
  case Instruction::CREATE2:
133
76.1k
    return vector<Operation>{
134
76.1k
      Operation{
135
76.1k
        Location::Memory,
136
76.1k
        Effect::Read,
137
76.1k
        1,
138
76.1k
        2,
139
76.1k
        {}
140
76.1k
      },
141
76.1k
      Operation{Location::Storage, Effect::Read, {}, {}, {}},
142
76.1k
      Operation{Location::Storage, Effect::Write, {}, {}, {}}
143
76.1k
    };
144
36.2k
  case Instruction::MSIZE:
145
    // This is just to satisfy the assert below.
146
36.2k
    return vector<Operation>{};
147
1.29M
  default:
148
1.29M
    assertThrow(storage(_instruction) == None && memory(_instruction) == None, AssemblyException, "");
149
2.79M
  }
150
1.29M
  return {};
151
2.79M
}
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
12.6M
{
221
12.6M
  if (_item.type() != evmasm::Operation)
222
0
    return false;
223
12.6M
  return evmasm::isDupInstruction(_item.instruction());
224
12.6M
}
225
226
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
227
12.6M
{
228
12.6M
  if (_item.type() != evmasm::Operation)
229
0
    return false;
230
12.6M
  return evmasm::isSwapInstruction(_item.instruction());
231
12.6M
}
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
3.27M
{
261
3.27M
  switch (_instruction)
262
3.27M
  {
263
45.7k
  case Instruction::RETURN:
264
91.4k
  case Instruction::SELFDESTRUCT:
265
137k
  case Instruction::STOP:
266
182k
  case Instruction::INVALID:
267
228k
  case Instruction::REVERT:
268
228k
    return true;
269
3.04M
  default:
270
3.04M
    return false;
271
3.27M
  }
272
3.27M
}
273
274
bool SemanticInformation::reverts(Instruction _instruction)
275
228k
{
276
228k
  switch (_instruction)
277
228k
  {
278
45.7k
    case Instruction::INVALID:
279
91.4k
    case Instruction::REVERT:
280
91.4k
      return true;
281
137k
    default:
282
137k
      return false;
283
228k
  }
284
228k
}
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
6.23M
{
318
  // These are not really functional.
319
6.23M
  if (isDupInstruction(_instruction) || isSwapInstruction(_instruction))
320
0
    return false;
321
6.23M
  InstructionInfo info = instructionInfo(_instruction);
322
6.23M
  if (info.sideEffects)
323
2.09M
    return false;
324
4.13M
  switch (_instruction)
325
4.13M
  {
326
0
  case Instruction::KECCAK256:
327
45.7k
  case Instruction::BALANCE:
328
73.4k
  case Instruction::SELFBALANCE:
329
119k
  case Instruction::EXTCODESIZE:
330
147k
  case Instruction::EXTCODEHASH:
331
176k
  case Instruction::RETURNDATASIZE:
332
222k
  case Instruction::SLOAD:
333
313k
  case Instruction::PC:
334
404k
  case Instruction::MSIZE:
335
496k
  case Instruction::GAS:
336
496k
    return false;
337
3.64M
  default:
338
3.64M
    return true;
339
4.13M
  }
340
0
  return true;
341
4.13M
}
342
343
bool SemanticInformation::canBeRemoved(Instruction _instruction)
344
6.45M
{
345
  // These are not really functional.
346
6.45M
  assertThrow(!isDupInstruction(_instruction) && !isSwapInstruction(_instruction), AssemblyException, "");
347
348
6.45M
  return !instructionInfo(_instruction).sideEffects;
349
6.45M
}
350
351
bool SemanticInformation::canBeRemovedIfNoMSize(Instruction _instruction)
352
3.27M
{
353
3.27M
  if (_instruction == Instruction::KECCAK256 || _instruction == Instruction::MLOAD)
354
91.4k
    return true;
355
3.18M
  else
356
3.18M
    return canBeRemoved(_instruction);
357
3.27M
}
358
359
SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction)
360
6.24M
{
361
6.24M
  switch (_instruction)
362
6.24M
  {
363
102k
  case Instruction::CALLDATACOPY:
364
190k
  case Instruction::CODECOPY:
365
313k
  case Instruction::EXTCODECOPY:
366
408k
  case Instruction::RETURNDATACOPY:
367
927k
  case Instruction::MSTORE:
368
995k
  case Instruction::MSTORE8:
369
1.04M
  case Instruction::CALL:
370
1.08M
  case Instruction::CALLCODE:
371
1.13M
  case Instruction::DELEGATECALL:
372
1.16M
  case Instruction::STATICCALL:
373
1.16M
    return SemanticInformation::Write;
374
375
45.7k
  case Instruction::CREATE:
376
74.1k
  case Instruction::CREATE2:
377
160k
  case Instruction::KECCAK256:
378
435k
  case Instruction::MLOAD:
379
480k
  case Instruction::MSIZE:
380
532k
  case Instruction::RETURN:
381
581k
  case Instruction::REVERT:
382
656k
  case Instruction::LOG0:
383
709k
  case Instruction::LOG1:
384
765k
  case Instruction::LOG2:
385
818k
  case Instruction::LOG3:
386
924k
  case Instruction::LOG4:
387
924k
    return SemanticInformation::Read;
388
389
4.15M
  default:
390
4.15M
    return SemanticInformation::None;
391
6.24M
  }
392
6.24M
}
393
394
bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
395
3.27M
{
396
3.27M
  switch (_instruction)
397
3.27M
  {
398
28.4k
  case Instruction::EXTCODEHASH:
399
74.1k
  case Instruction::EXTCODESIZE:
400
102k
  case Instruction::RETURNDATASIZE:
401
148k
  case Instruction::BALANCE:
402
176k
  case Instruction::SELFBALANCE:
403
222k
  case Instruction::SLOAD:
404
267k
  case Instruction::KECCAK256:
405
313k
  case Instruction::MLOAD:
406
313k
    return true;
407
408
2.95M
  default:
409
2.95M
    return movable(_instruction);
410
3.27M
  }
411
3.27M
}
412
413
SemanticInformation::Effect SemanticInformation::storage(Instruction _instruction)
414
6.36M
{
415
6.36M
  switch (_instruction)
416
6.36M
  {
417
45.7k
  case Instruction::CALL:
418
91.4k
  case Instruction::CALLCODE:
419
137k
  case Instruction::DELEGATECALL:
420
182k
  case Instruction::CREATE:
421
211k
  case Instruction::CREATE2:
422
1.22M
  case Instruction::SSTORE:
423
1.22M
    return SemanticInformation::Write;
424
425
197k
  case Instruction::SLOAD:
426
226k
  case Instruction::STATICCALL:
427
226k
    return SemanticInformation::Read;
428
429
4.91M
  default:
430
4.91M
    return SemanticInformation::None;
431
6.36M
  }
432
6.36M
}
433
434
SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruction)
435
3.56M
{
436
3.56M
  switch (_instruction)
437
3.56M
  {
438
45.7k
  case Instruction::CALL:
439
91.4k
  case Instruction::CALLCODE:
440
137k
  case Instruction::DELEGATECALL:
441
182k
  case Instruction::CREATE:
442
211k
  case Instruction::CREATE2:
443
258k
  case Instruction::SELFDESTRUCT:
444
286k
  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
286k
    return SemanticInformation::Write;
448
449
45.7k
  case Instruction::EXTCODESIZE:
450
74.1k
  case Instruction::EXTCODEHASH:
451
102k
  case Instruction::RETURNDATASIZE:
452
148k
  case Instruction::BALANCE:
453
176k
  case Instruction::SELFBALANCE:
454
214k
  case Instruction::RETURNDATACOPY:
455
271k
  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
271k
    return SemanticInformation::Read;
459
460
3.00M
  default:
461
3.00M
    return SemanticInformation::None;
462
3.56M
  }
463
3.56M
}
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
}