Coverage Report

Created: 2025-06-24 07:59

/src/solidity/test/tools/ossfuzz/protoToSol.h
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
#pragma once
19
20
#include <test/tools/ossfuzz/solProto.pb.h>
21
22
#include <random>
23
#include <string>
24
#include <utility>
25
#include <variant>
26
27
namespace solidity::test::solprotofuzzer
28
{
29
/// Random number generator that is seeded with a fuzzer
30
/// supplied unsigned integer.
31
struct SolRandomNumGenerator
32
{
33
  using RandomEngine = std::minstd_rand;
34
35
273
  explicit SolRandomNumGenerator(unsigned _seed): m_random(RandomEngine(_seed)) {}
36
37
  /// @returns a pseudo random unsigned integer
38
  unsigned operator()()
39
0
  {
40
0
    return static_cast<unsigned>(m_random());
41
0
  }
42
43
  RandomEngine m_random;
44
};
45
46
/* There are two types of tests created by the converter:
47
 * - library test
48
 * - contract test
49
 *
50
 * The template for library test is the following:
51
 *
52
 * // Library generated from fuzzer protobuf specification
53
 * library L0 {
54
 *      function f0(uint) public view returns (uint) {
55
 *          return 31337;
56
 *      }
57
 *      function f1(uint) public pure returns (uint) {
58
 *          return 455;
59
 *      }
60
 * }
61
 * library L1 {
62
 *      function f0(uint) external view returns (uint) {
63
 *          return 607;
64
 *      }
65
 * }
66
 *
67
 * // Test entry point
68
 * contract C {
69
 *     // Uses a single pseudo randomly chosen library
70
 *     // and calls a pseudo randomly chosen function
71
 *     // returning a non-zero error code on failure or
72
 *     // a zero uint when test passes.
73
 *     using L0 for uint;
74
 *     function test() public pure returns (uint) {
75
 *          uint x;
76
 *          if (x.f1() != 455)
77
 *              return 1;
78
 *          return 0;
79
 *     }
80
 * }
81
 *
82
 * The template for contract test is the following
83
 * // Contracts generated from fuzzer protobuf specification
84
 * contract C0B {
85
 *      function f0() public pure virtual returns (uint)
86
 *      {
87
 *          return 42;
88
 *      }
89
 * }
90
 * contract C0 is C0B {
91
 *      function f0() public pure override returns (uint)
92
 *      {
93
 *          return 1337;
94
 *      }
95
 * }
96
 *
97
 * // Test entry point
98
 * contract C {
99
 *      // Invokes one or more contract functions returning
100
 *      // a non-zero error code for failure, a zero uint
101
 *      // when all tests pass
102
 *      function test() public pure returns (uint)
103
 *      {
104
 *          C0 tc0 = new C0();
105
 *          if (tc0.f0() != 1337)
106
 *              return 1;
107
 *          C0B tc1 = new C0B();
108
 *          if (tc1.f0() != 42)
109
 *              return 2;
110
 *          // Expected return value if all tests pass
111
 *          return 0;
112
 *      }
113
 * }
114
 */
115
class ProtoConverter
116
{
117
public:
118
273
  ProtoConverter() {}
119
  ProtoConverter(ProtoConverter const&) = delete;
120
  ProtoConverter(ProtoConverter&&) = delete;
121
  std::string protoToSolidity(Program const&);
122
  /// @returns true if test calls a library function, false
123
  /// otherwise
124
  bool libraryTest() const;
125
  /// @returns name of the library under test
126
  std::string libraryName() const;
127
private:
128
  /// Variant type that points to one of contract, interface, library protobuf messages
129
  using CIL = std::variant<Contract const*, Interface const*, Library const*>;
130
  /// Protobuf message visitors that accept a const reference to a protobuf message
131
  /// type and return its solidity translation.
132
  std::string visit(Program const&);
133
  std::string visit(TestContract const&);
134
  std::string visit(ContractType const&);
135
  std::string visit(Interface const& _interface);
136
  std::string visit(Library const& _library);
137
  std::string visit(Contract const& _contract);
138
  /// @returns a string pair containing a library declaration (relevant for library
139
  /// tests only) and a solidity test case
140
  std::pair<std::string, std::string> generateTestCase(TestContract const& _testContract);
141
  /// @returns name of a program i.e., contract, library or interface
142
  std::string programName(CIL _program);
143
  /// @returns a tuple containing the names of the library and function under
144
  /// test, and its expected output.
145
  std::tuple<std::string, std::string, std::string> pseudoRandomLibraryTest();
146
  /// Performs bookkeeping for a fuzzer-supplied program
147
  void openProgramScope(CIL _program);
148
  /// @returns a deterministic pseudo random unsigned integer
149
  unsigned randomNumber();
150
  /// @returns true if fuzzer supplied Library protobuf message
151
  /// contains zero functions, false otherwise.
152
  static bool emptyLibrary(Library const& _library)
153
0
  {
154
0
    return _library.funcdef_size() == 0;
155
0
  }
156
  /// @returns true if there are no valid library test cases, false
157
  /// otherwise.
158
  bool emptyLibraryTests()
159
273
  {
160
273
    return m_libraryTests.empty();
161
273
  }
162
  /// @returns true if there are no valid contract test cases, false
163
  /// otherwise.
164
  bool emptyContractTests()
165
0
  {
166
0
    return m_contractTests.empty();
167
0
  }
168
  /// Numeric suffix that is part of program names e.g., "0" in "C0"
169
  unsigned m_programNumericSuffix = 0;
170
  /// Flag that states whether library call is tested (true) or not (false).
171
  bool m_libraryTest = false;
172
  /// A smart pointer to fuzzer driven random number generator
173
  std::shared_ptr<SolRandomNumGenerator> m_randomGen;
174
  /// Maps protobuf program to its string name
175
  std::map<CIL, std::string> m_programNameMap;
176
  /// List of tuples containing library name, function and its expected output
177
  std::vector<std::tuple<std::string, std::string, std::string>> m_libraryTests;
178
  /// Maps contract name to a map of function names and their expected output
179
  std::map<std::string, std::map<std::string, std::string>> m_contractTests;
180
  /// Name of the library under test, relevant if m_libraryTest is set
181
  std::string m_libraryName;
182
  /// Maximum number of local variables in test function to avoid stack too deep
183
  /// errors
184
  static unsigned constexpr s_maxVars = 15;
185
};
186
}