Coverage Report

Created: 2022-08-24 06:55

/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
24.8M
{
203
24.8M
  if (_item.type() != evmasm::Operation)
204
11.0M
    return false;
205
13.8M
  switch (_item.instruction())
206
13.8M
  {
207
186k
  case Instruction::ADD:
208
186k
  case Instruction::MUL:
209
186k
  case Instruction::EQ:
210
186k
  case Instruction::AND:
211
186k
  case Instruction::OR:
212
186k
  case Instruction::XOR:
213
186k
    return true;
214
13.6M
  default:
215
13.6M
    return false;
216
13.8M
  }
217
13.8M
}
218
219
bool SemanticInformation::isDupInstruction(AssemblyItem const& _item)
220
675M
{
221
675M
  if (_item.type() != evmasm::Operation)
222
273M
    return false;
223
401M
  return evmasm::isDupInstruction(_item.instruction());
224
675M
}
225
226
bool SemanticInformation::isSwapInstruction(AssemblyItem const& _item)
227
102M
{
228
102M
  if (_item.type() != evmasm::Operation)
229
17.0M
    return false;
230
85.2M
  return evmasm::isSwapInstruction(_item.instruction());
231
102M
}
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
76
{
261
76
  switch (_instruction)
262
76
  {
263
1
  case Instruction::RETURN:
264
2
  case Instruction::SELFDESTRUCT:
265
3
  case Instruction::STOP:
266
4
  case Instruction::INVALID:
267
5
  case Instruction::REVERT:
268
5
    return true;
269
71
  default:
270
71
    return false;
271
76
  }
272
76
}
273
274
bool SemanticInformation::reverts(Instruction _instruction)
275
5
{
276
5
  switch (_instruction)
277
5
  {
278
1
    case Instruction::INVALID:
279
2
    case Instruction::REVERT:
280
2
      return true;
281
3
    default:
282
3
      return false;
283
5
  }
284
5
}
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
144
{
318
  // These are not really functional.
319
144
  if (isDupInstruction(_instruction) || isSwapInstruction(_instruction))
320
0
    return false;
321
144
  InstructionInfo info = instructionInfo(_instruction);
322
144
  if (info.sideEffects)
323
48
    return false;
324
96
  switch (_instruction)
325
96
  {
326
0
  case Instruction::KECCAK256:
327
1
  case Instruction::BALANCE:
328
2
  case Instruction::SELFBALANCE:
329
3
  case Instruction::EXTCODESIZE:
330
4
  case Instruction::EXTCODEHASH:
331
5
  case Instruction::RETURNDATASIZE:
332
6
  case Instruction::SLOAD:
333
8
  case Instruction::PC:
334
10
  case Instruction::MSIZE:
335
12
  case Instruction::GAS:
336
12
    return false;
337
84
  default:
338
84
    return true;
339
96
  }
340
0
  return true;
341
96
}
342
343
bool SemanticInformation::canBeRemoved(Instruction _instruction)
344
150
{
345
  // These are not really functional.
346
150
  assertThrow(!isDupInstruction(_instruction) && !isSwapInstruction(_instruction), AssemblyException, "");
347
348
150
  return !instructionInfo(_instruction).sideEffects;
349
150
}
350
351
bool SemanticInformation::canBeRemovedIfNoMSize(Instruction _instruction)
352
76
{
353
76
  if (_instruction == Instruction::KECCAK256 || _instruction == Instruction::MLOAD)
354
2
    return true;
355
74
  else
356
74
    return canBeRemoved(_instruction);
357
76
}
358
359
SemanticInformation::Effect SemanticInformation::memory(Instruction _instruction)
360
76
{
361
76
  switch (_instruction)
362
76
  {
363
1
  case Instruction::CALLDATACOPY:
364
2
  case Instruction::CODECOPY:
365
3
  case Instruction::EXTCODECOPY:
366
4
  case Instruction::RETURNDATACOPY:
367
5
  case Instruction::MSTORE:
368
6
  case Instruction::MSTORE8:
369
7
  case Instruction::CALL:
370
8
  case Instruction::CALLCODE:
371
9
  case Instruction::DELEGATECALL:
372
10
  case Instruction::STATICCALL:
373
10
    return SemanticInformation::Write;
374
375
1
  case Instruction::CREATE:
376
2
  case Instruction::CREATE2:
377
3
  case Instruction::KECCAK256:
378
4
  case Instruction::MLOAD:
379
5
  case Instruction::MSIZE:
380
6
  case Instruction::RETURN:
381
7
  case Instruction::REVERT:
382
8
  case Instruction::LOG0:
383
9
  case Instruction::LOG1:
384
10
  case Instruction::LOG2:
385
11
  case Instruction::LOG3:
386
12
  case Instruction::LOG4:
387
12
    return SemanticInformation::Read;
388
389
54
  default:
390
54
    return SemanticInformation::None;
391
76
  }
392
76
}
393
394
bool SemanticInformation::movableApartFromEffects(Instruction _instruction)
395
76
{
396
76
  switch (_instruction)
397
76
  {
398
1
  case Instruction::EXTCODEHASH:
399
2
  case Instruction::EXTCODESIZE:
400
3
  case Instruction::RETURNDATASIZE:
401
4
  case Instruction::BALANCE:
402
5
  case Instruction::SELFBALANCE:
403
6
  case Instruction::SLOAD:
404
7
  case Instruction::KECCAK256:
405
8
  case Instruction::MLOAD:
406
8
    return true;
407
408
68
  default:
409
68
    return movable(_instruction);
410
76
  }
411
76
}
412
413
SemanticInformation::Effect SemanticInformation::storage(Instruction _instruction)
414
76
{
415
76
  switch (_instruction)
416
76
  {
417
1
  case Instruction::CALL:
418
2
  case Instruction::CALLCODE:
419
3
  case Instruction::DELEGATECALL:
420
4
  case Instruction::CREATE:
421
5
  case Instruction::CREATE2:
422
6
  case Instruction::SSTORE:
423
6
    return SemanticInformation::Write;
424
425
1
  case Instruction::SLOAD:
426
2
  case Instruction::STATICCALL:
427
2
    return SemanticInformation::Read;
428
429
68
  default:
430
68
    return SemanticInformation::None;
431
76
  }
432
76
}
433
434
SemanticInformation::Effect SemanticInformation::otherState(Instruction _instruction)
435
76
{
436
76
  switch (_instruction)
437
76
  {
438
1
  case Instruction::CALL:
439
2
  case Instruction::CALLCODE:
440
3
  case Instruction::DELEGATECALL:
441
4
  case Instruction::CREATE:
442
5
  case Instruction::CREATE2:
443
6
  case Instruction::SELFDESTRUCT:
444
7
  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
7
    return SemanticInformation::Write;
448
449
1
  case Instruction::EXTCODESIZE:
450
2
  case Instruction::EXTCODEHASH:
451
3
  case Instruction::RETURNDATASIZE:
452
4
  case Instruction::BALANCE:
453
5
  case Instruction::SELFBALANCE:
454
6
  case Instruction::RETURNDATACOPY:
455
7
  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
7
    return SemanticInformation::Read;
459
460
62
  default:
461
62
    return SemanticInformation::None;
462
76
  }
463
76
}
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
}