Coverage Report

Created: 2026-07-13 07:08

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/solidity/libsolidity/interface/GasEstimator.cpp
Line
Count
Source
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
 * @author Christian <c@ethdev.com>
20
 * @date 2015
21
 * Gas consumption estimator working alongside the AST.
22
 */
23
24
#include <libsolidity/interface/GasEstimator.h>
25
26
#include <libsolidity/ast/AST.h>
27
#include <libsolidity/ast/ASTVisitor.h>
28
#include <libsolidity/codegen/CompilerUtils.h>
29
30
#include <libevmasm/ControlFlowGraph.h>
31
#include <libevmasm/KnownState.h>
32
#include <libevmasm/PathGasMeter.h>
33
#include <libsolutil/FunctionSelector.h>
34
#include <libsolutil/Keccak256.h>
35
36
#include <functional>
37
#include <map>
38
#include <memory>
39
40
using namespace solidity;
41
using namespace solidity::evmasm;
42
using namespace solidity::frontend;
43
using namespace solidity::langutil;
44
45
GasEstimator::GasConsumption GasEstimator::functionalEstimation(
46
  AssemblyItems const& _items,
47
  std::string const& _signature
48
) const
49
0
{
50
0
  auto state = std::make_shared<KnownState>();
51
52
0
  if (!_signature.empty())
53
0
  {
54
0
    ExpressionClasses& classes = state->expressionClasses();
55
0
    using Id = ExpressionClasses::Id;
56
0
    using Ids = std::vector<Id>;
57
0
    Id hashValue = classes.find(u256(util::selectorFromSignatureU32(_signature)));
58
0
    Id calldata = classes.find(Instruction::CALLDATALOAD, Ids{classes.find(u256(0))});
59
0
    if (!m_evmVersion.hasBitwiseShifting())
60
      // div(calldataload(0), 1 << 224) equals to hashValue
61
0
      classes.forceEqual(
62
0
        hashValue,
63
0
        Instruction::DIV,
64
0
        Ids{calldata, classes.find(u256(1) << 224)}
65
0
      );
66
0
    else
67
      // shr(0xe0, calldataload(0)) equals to hashValue
68
0
      classes.forceEqual(
69
0
        hashValue,
70
0
        Instruction::SHR,
71
0
        Ids{classes.find(u256(0xe0)), calldata}
72
0
      );
73
    // lt(calldatasize(), 4) equals to 0 (ignore the shortcut for fallback functions)
74
0
    classes.forceEqual(
75
0
      classes.find(u256(0)),
76
0
      Instruction::LT,
77
0
      Ids{classes.find(Instruction::CALLDATASIZE), classes.find(u256(4))}
78
0
    );
79
0
  }
80
81
0
  return PathGasMeter::estimateMax(_items, m_evmVersion, 0, state);
82
0
}
83
84
GasEstimator::GasConsumption GasEstimator::functionalEstimation(
85
  AssemblyItems const& _items,
86
  size_t const& _offset,
87
  FunctionDefinition const& _function
88
) const
89
0
{
90
0
  auto state = std::make_shared<KnownState>();
91
92
0
  unsigned parametersSize = CompilerUtils::sizeOnStack(_function.parameters());
93
0
  if (parametersSize > m_evmVersion.reachableStackDepth())
94
0
    return GasConsumption::infinite();
95
96
  // Store an invalid return value on the stack, so that the path estimator breaks upon reaching
97
  // the return jump.
98
0
  AssemblyItem invalidTag(PushTag, u256(-0x10));
99
0
  state->feedItem(invalidTag, true);
100
0
  if (parametersSize > 0)
101
0
    state->feedItem(swapInstruction(parametersSize));
102
103
0
  return PathGasMeter::estimateMax(_items, m_evmVersion, _offset, state);
104
0
}
105
106
std::set<ASTNode const*> GasEstimator::finestNodesAtLocation(
107
  std::vector<ASTNode const*> const& _roots
108
)
109
0
{
110
0
  std::map<SourceLocation, ASTNode const*> locations;
111
0
  std::set<ASTNode const*> nodes;
112
0
  SimpleASTVisitor visitor([](ASTNode const&) { return false; }, [&](ASTNode const& _n)
113
0
  {
114
0
    if (!locations.count(_n.location()))
115
0
    {
116
0
      locations[_n.location()] = &_n;
117
0
      nodes.insert(&_n);
118
0
    }
119
0
  });
120
121
0
  for (ASTNode const* root: _roots)
122
0
    root->accept(visitor);
123
0
  return nodes;
124
0
}