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 * Component that verifies overloads, abstract contracts, function clashes and others
20 * checks at contract or function level.
21 */
22
23 #include <libsolidity/analysis/ContractLevelChecker.h>
24
25 #include <libsolidity/ast/AST.h>
26 #include <libsolidity/ast/TypeProvider.h>
27 #include <libsolidity/analysis/TypeChecker.h>
28 #include <libsolutil/FunctionSelector.h>
29 #include <liblangutil/ErrorReporter.h>
30
31 #include <range/v3/view/reverse.hpp>
32
33 using namespace std;
34 using namespace solidity;
35 using namespace solidity::langutil;
36 using namespace solidity::frontend;
37
38 namespace
39 {
40
41 template <class T, class B>
hasEqualParameters(T const & _a,B const & _b)42 bool hasEqualParameters(T const& _a, B const& _b)
43 {
44 return FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
45 *FunctionType(_b).asExternallyCallableFunction(false)
46 );
47 }
48
49 template<typename T>
filterDeclarations(map<ASTString,vector<Declaration const * >> const & _declarations)50 map<ASTString, vector<T const*>> filterDeclarations(
51 map<ASTString, vector<Declaration const*>> const& _declarations)
52 {
53 map<ASTString, vector<T const*>> filteredDeclarations;
54 for (auto const& [name, overloads]: _declarations)
55 for (auto const* declaration: overloads)
56 if (auto typedDeclaration = dynamic_cast<T const*>(declaration))
57 filteredDeclarations[name].push_back(typedDeclaration);
58 return filteredDeclarations;
59 }
60
61 }
62
check(SourceUnit const & _sourceUnit)63 bool ContractLevelChecker::check(SourceUnit const& _sourceUnit)
64 {
65 bool noErrors = true;
66 findDuplicateDefinitions(
67 filterDeclarations<FunctionDefinition>(*_sourceUnit.annotation().exportedSymbols)
68 );
69 // This check flags duplicate free events when free events become
70 // a Solidity feature
71 findDuplicateDefinitions(
72 filterDeclarations<EventDefinition>(*_sourceUnit.annotation().exportedSymbols)
73 );
74 if (Error::containsErrors(m_errorReporter.errors()))
75 noErrors = false;
76 for (ASTPointer<ASTNode> const& node: _sourceUnit.nodes())
77 if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
78 if (!check(*contract))
79 noErrors = false;
80 return noErrors;
81 }
82
check(ContractDefinition const & _contract)83 bool ContractLevelChecker::check(ContractDefinition const& _contract)
84 {
85 _contract.annotation().unimplementedDeclarations = std::vector<Declaration const*>();
86
87 checkDuplicateFunctions(_contract);
88 checkDuplicateEvents(_contract);
89 checkReceiveFunction(_contract);
90 m_overrideChecker.check(_contract);
91 checkBaseConstructorArguments(_contract);
92 checkAbstractDefinitions(_contract);
93 checkExternalTypeClashes(_contract);
94 checkHashCollisions(_contract);
95 checkLibraryRequirements(_contract);
96 checkBaseABICompatibility(_contract);
97 checkPayableFallbackWithoutReceive(_contract);
98 checkStorageSize(_contract);
99
100 return !Error::containsErrors(m_errorReporter.errors());
101 }
102
checkDuplicateFunctions(ContractDefinition const & _contract)103 void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
104 {
105 /// Checks that two functions with the same name defined in this contract have different
106 /// argument types and that there is at most one constructor.
107 map<string, vector<FunctionDefinition const*>> functions;
108 FunctionDefinition const* constructor = nullptr;
109 FunctionDefinition const* fallback = nullptr;
110 FunctionDefinition const* receive = nullptr;
111 for (FunctionDefinition const* function: _contract.definedFunctions())
112 if (function->isConstructor())
113 {
114 if (constructor)
115 m_errorReporter.declarationError(
116 7997_error,
117 function->location(),
118 SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
119 "More than one constructor defined."
120 );
121 constructor = function;
122 }
123 else if (function->isFallback())
124 {
125 if (fallback)
126 m_errorReporter.declarationError(
127 7301_error,
128 function->location(),
129 SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
130 "Only one fallback function is allowed."
131 );
132 fallback = function;
133 }
134 else if (function->isReceive())
135 {
136 if (receive)
137 m_errorReporter.declarationError(
138 4046_error,
139 function->location(),
140 SecondarySourceLocation().append("Another declaration is here:", receive->location()),
141 "Only one receive function is allowed."
142 );
143 receive = function;
144 }
145 else
146 {
147 solAssert(!function->name().empty(), "");
148 functions[function->name()].push_back(function);
149 }
150
151 findDuplicateDefinitions(functions);
152 }
153
checkDuplicateEvents(ContractDefinition const & _contract)154 void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract)
155 {
156 /// Checks that two events with the same name defined in this contract have different
157 /// argument types
158 map<string, vector<EventDefinition const*>> events;
159 for (auto const* contract: _contract.annotation().linearizedBaseContracts)
160 for (EventDefinition const* event: contract->events())
161 events[event->name()].push_back(event);
162
163 findDuplicateDefinitions(events);
164 }
165
checkReceiveFunction(ContractDefinition const & _contract)166 void ContractLevelChecker::checkReceiveFunction(ContractDefinition const& _contract)
167 {
168 for (FunctionDefinition const* function: _contract.definedFunctions())
169 {
170 solAssert(function, "");
171 if (function->isReceive())
172 {
173 if (function->libraryFunction())
174 m_errorReporter.declarationError(4549_error, function->location(), "Libraries cannot have receive ether functions.");
175
176 if (function->stateMutability() != StateMutability::Payable)
177 m_errorReporter.declarationError(
178 7793_error,
179 function->location(),
180 "Receive ether function must be payable, but is \"" +
181 stateMutabilityToString(function->stateMutability()) +
182 "\"."
183 );
184 if (function->visibility() != Visibility::External)
185 m_errorReporter.declarationError(4095_error, function->location(), "Receive ether function must be defined as \"external\".");
186
187 if (!function->returnParameters().empty())
188 m_errorReporter.fatalDeclarationError(6899_error, function->returnParameterList()->location(), "Receive ether function cannot return values.");
189 if (!function->parameters().empty())
190 m_errorReporter.fatalDeclarationError(6857_error, function->parameterList().location(), "Receive ether function cannot take parameters.");
191 }
192 }
193 }
194
195 template <class T>
findDuplicateDefinitions(map<string,vector<T>> const & _definitions)196 void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions)
197 {
198 for (auto const& it: _definitions)
199 {
200 vector<T> const& overloads = it.second;
201 set<size_t> reported;
202 for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
203 {
204 SecondarySourceLocation ssl;
205
206 for (size_t j = i + 1; j < overloads.size(); ++j)
207 if (hasEqualParameters(*overloads[i], *overloads[j]))
208 {
209 solAssert(
210 (
211 dynamic_cast<ContractDefinition const*>(overloads[i]->scope()) &&
212 dynamic_cast<ContractDefinition const*>(overloads[j]->scope()) &&
213 overloads[i]->name() == overloads[j]->name()
214 ) ||
215 (
216 dynamic_cast<SourceUnit const*>(overloads[i]->scope()) &&
217 dynamic_cast<SourceUnit const*>(overloads[j]->scope())
218 ),
219 "Override is neither a namesake function/event in contract scope nor "
220 "a free function/event (alias)."
221 );
222 ssl.append("Other declaration is here:", overloads[j]->location());
223 reported.insert(j);
224 }
225
226 if (ssl.infos.size() > 0)
227 {
228 ErrorId error;
229 string message;
230 if constexpr (is_same_v<T, FunctionDefinition const*>)
231 {
232 error = 1686_error;
233 message = "Function with same name and parameter types defined twice.";
234 }
235 else
236 {
237 static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
238 error = 5883_error;
239 message = "Event with same name and parameter types defined twice.";
240 }
241
242 ssl.limitSize(message);
243
244 m_errorReporter.declarationError(
245 error,
246 overloads[i]->location(),
247 ssl,
248 message
249 );
250 }
251 }
252 }
253 }
254
checkAbstractDefinitions(ContractDefinition const & _contract)255 void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _contract)
256 {
257 // Collects functions, static variable getters and modifiers. If they
258 // override (unimplemented) base class ones, they are replaced.
259 set<OverrideProxy, OverrideProxy::CompareBySignature> proxies;
260
261 auto registerProxy = [&proxies](OverrideProxy const& _overrideProxy)
262 {
263 // Overwrite an existing proxy, if it exists.
264 if (!_overrideProxy.unimplemented())
265 proxies.erase(_overrideProxy);
266
267 proxies.insert(_overrideProxy);
268 };
269
270 // Search from base to derived, collect all functions and modifiers and
271 // update proxies.
272 for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse)
273 {
274 for (VariableDeclaration const* v: contract->stateVariables())
275 if (v->isPartOfExternalInterface())
276 registerProxy(OverrideProxy(v));
277
278 for (FunctionDefinition const* function: contract->definedFunctions())
279 if (!function->isConstructor())
280 registerProxy(OverrideProxy(function));
281
282 for (ModifierDefinition const* modifier: contract->functionModifiers())
283 registerProxy(OverrideProxy(modifier));
284 }
285
286 // Set to not fully implemented if at least one flag is false.
287 // Note that `_contract.annotation().unimplementedDeclarations` has already been
288 // pre-filled by `checkBaseConstructorArguments`.
289 //
290 for (auto const& proxy: proxies)
291 if (proxy.unimplemented())
292 _contract.annotation().unimplementedDeclarations->push_back(proxy.declaration());
293
294 if (_contract.abstract())
295 {
296 if (_contract.contractKind() == ContractKind::Interface)
297 m_errorReporter.typeError(9348_error, _contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly.");
298 else if (_contract.contractKind() == ContractKind::Library)
299 m_errorReporter.typeError(9571_error, _contract.location(), "Libraries cannot be abstract.");
300 else
301 solAssert(_contract.contractKind() == ContractKind::Contract, "");
302 }
303
304 // For libraries, we emit errors on function-level, so this is fine as long as we do
305 // not have inheritance for libraries.
306 if (
307 _contract.contractKind() == ContractKind::Contract &&
308 !_contract.abstract() &&
309 !_contract.annotation().unimplementedDeclarations->empty()
310 )
311 {
312 SecondarySourceLocation ssl;
313 for (auto declaration: *_contract.annotation().unimplementedDeclarations)
314 ssl.append("Missing implementation: ", declaration->location());
315 m_errorReporter.typeError(
316 3656_error,
317 _contract.location(),
318 ssl,
319 "Contract \"" + *_contract.annotation().canonicalName + "\" should be marked as abstract."
320 );
321 }
322 }
323
324
checkBaseConstructorArguments(ContractDefinition const & _contract)325 void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract)
326 {
327 vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
328
329 // Determine the arguments that are used for the base constructors.
330 for (ContractDefinition const* contract: bases)
331 {
332 if (FunctionDefinition const* constructor = contract->constructor())
333 for (auto const& modifier: constructor->modifiers())
334 if (auto baseContract = dynamic_cast<ContractDefinition const*>(
335 modifier->name().annotation().referencedDeclaration
336 ))
337 {
338 if (modifier->arguments())
339 {
340 if (baseContract->constructor())
341 annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
342 }
343 else
344 m_errorReporter.declarationError(
345 1563_error,
346 modifier->location(),
347 "Modifier-style base constructor call without arguments."
348 );
349 }
350
351 for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
352 {
353 ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
354 base->name().annotation().referencedDeclaration
355 );
356 solAssert(baseContract, "");
357
358 if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
359 annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
360 }
361 }
362
363 // check that we get arguments for all base constructors that need it.
364 // If not mark the contract as abstract (not fully implemented)
365 for (ContractDefinition const* contract: bases)
366 if (FunctionDefinition const* constructor = contract->constructor())
367 if (contract != &_contract && !constructor->parameters().empty())
368 if (!_contract.annotation().baseConstructorArguments.count(constructor))
369 _contract.annotation().unimplementedDeclarations->push_back(constructor);
370 }
371
annotateBaseConstructorArguments(ContractDefinition const & _currentContract,FunctionDefinition const * _baseConstructor,ASTNode const * _argumentNode)372 void ContractLevelChecker::annotateBaseConstructorArguments(
373 ContractDefinition const& _currentContract,
374 FunctionDefinition const* _baseConstructor,
375 ASTNode const* _argumentNode
376 )
377 {
378 solAssert(_baseConstructor, "");
379 solAssert(_argumentNode, "");
380
381 auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
382 std::make_pair(_baseConstructor, _argumentNode)
383 );
384 if (!insertionResult.second)
385 {
386 ASTNode const* previousNode = insertionResult.first->second;
387
388 SourceLocation const* mainLocation = nullptr;
389 SecondarySourceLocation ssl;
390
391 if (
392 _currentContract.location().contains(previousNode->location()) ||
393 _currentContract.location().contains(_argumentNode->location())
394 )
395 {
396 mainLocation = &previousNode->location();
397 ssl.append("Second constructor call is here:", _argumentNode->location());
398 }
399 else
400 {
401 mainLocation = &_currentContract.location();
402 ssl.append("First constructor call is here:", _argumentNode->location());
403 ssl.append("Second constructor call is here:", previousNode->location());
404 }
405
406 m_errorReporter.declarationError(
407 3364_error,
408 *mainLocation,
409 ssl,
410 "Base constructor arguments given twice."
411 );
412 }
413
414 }
415
checkExternalTypeClashes(ContractDefinition const & _contract)416 void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract)
417 {
418 map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
419 for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
420 {
421 for (FunctionDefinition const* f: contract->definedFunctions())
422 if (f->isPartOfExternalInterface())
423 {
424 auto functionType = TypeProvider::function(*f);
425 // under non error circumstances this should be true
426 if (functionType->interfaceFunctionType())
427 externalDeclarations[functionType->externalSignature()].emplace_back(
428 f, functionType->asExternallyCallableFunction(false)
429 );
430 }
431 for (VariableDeclaration const* v: contract->stateVariables())
432 if (v->isPartOfExternalInterface())
433 {
434 auto functionType = TypeProvider::function(*v);
435 // under non error circumstances this should be true
436 if (functionType->interfaceFunctionType())
437 externalDeclarations[functionType->externalSignature()].emplace_back(
438 v, functionType->asExternallyCallableFunction(false)
439 );
440 }
441 }
442 for (auto const& it: externalDeclarations)
443 for (size_t i = 0; i < it.second.size(); ++i)
444 for (size_t j = i + 1; j < it.second.size(); ++j)
445 if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
446 m_errorReporter.typeError(
447 9914_error,
448 it.second[j].first->location(),
449 "Function overload clash during conversion to external types for arguments."
450 );
451 }
452
checkHashCollisions(ContractDefinition const & _contract)453 void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract)
454 {
455 set<util::FixedHash<4>> hashes;
456 for (auto const& it: _contract.interfaceFunctionList())
457 {
458 util::FixedHash<4> const& hash = it.first;
459 if (hashes.count(hash))
460 m_errorReporter.fatalTypeError(
461 1860_error,
462 _contract.location(),
463 string("Function signature hash collision for ") + it.second->externalSignature()
464 );
465 hashes.insert(hash);
466 }
467 }
468
checkLibraryRequirements(ContractDefinition const & _contract)469 void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
470 {
471 if (!_contract.isLibrary())
472 return;
473
474 if (!_contract.baseContracts().empty())
475 m_errorReporter.typeError(9469_error, _contract.location(), "Library is not allowed to inherit.");
476
477 for (auto const& var: _contract.stateVariables())
478 if (!var->isConstant())
479 m_errorReporter.typeError(9957_error, var->location(), "Library cannot have non-constant state variables");
480 }
481
checkBaseABICompatibility(ContractDefinition const & _contract)482 void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _contract)
483 {
484 if (*_contract.sourceUnit().annotation().useABICoderV2)
485 return;
486
487 if (_contract.isLibrary())
488 {
489 solAssert(
490 _contract.baseContracts().empty() || m_errorReporter.hasErrors(),
491 "Library is not allowed to inherit"
492 );
493 return;
494 }
495
496 SecondarySourceLocation errors;
497
498 // interfaceFunctionList contains all inherited functions as well
499 for (auto const& func: _contract.interfaceFunctionList())
500 {
501 solAssert(func.second->hasDeclaration(), "Function has no declaration?!");
502
503 if (!*func.second->declaration().sourceUnit().annotation().useABICoderV2)
504 continue;
505
506 auto const& currentLoc = func.second->declaration().location();
507
508 for (Type const* paramType: func.second->parameterTypes() + func.second->returnParameterTypes())
509 if (!TypeChecker::typeSupportedByOldABIEncoder(*paramType, false))
510 {
511 errors.append("Type only supported by ABIEncoderV2", currentLoc);
512 break;
513 }
514 }
515
516 if (!errors.infos.empty())
517 m_errorReporter.fatalTypeError(
518 6594_error,
519 _contract.location(),
520 errors,
521 std::string("Contract \"") +
522 _contract.name() +
523 "\" does not use ABI coder v2 but wants to inherit from a contract " +
524 "which uses types that require it. " +
525 "Use \"pragma abicoder v2;\" for the inheriting contract as well to enable the feature."
526 );
527
528 }
529
checkPayableFallbackWithoutReceive(ContractDefinition const & _contract)530 void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition const& _contract)
531 {
532 if (auto const* fallback = _contract.fallbackFunction())
533 if (fallback->isPayable() && !_contract.interfaceFunctionList().empty() && !_contract.receiveFunction())
534 m_errorReporter.warning(
535 3628_error,
536 _contract.location(),
537 "This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.",
538 SecondarySourceLocation{}.append("The payable fallback function is defined here.", fallback->location())
539 );
540 }
541
checkStorageSize(ContractDefinition const & _contract)542 void ContractLevelChecker::checkStorageSize(ContractDefinition const& _contract)
543 {
544 bigint size = 0;
545 for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts | ranges::views::reverse)
546 for (VariableDeclaration const* variable: contract->stateVariables())
547 if (!(variable->isConstant() || variable->immutable()))
548 {
549 size += variable->annotation().type->storageSizeUpperBound();
550 if (size >= bigint(1) << 256)
551 {
552 m_errorReporter.typeError(7676_error, _contract.location(), "Contract requires too much storage.");
553 break;
554 }
555 }
556 }
557