Skip to content

Commit

Permalink
Use all referenced errors.
Browse files Browse the repository at this point in the history
  • Loading branch information
chriseth committed Mar 18, 2021
1 parent fbd46a7 commit 69d6b62
Show file tree
Hide file tree
Showing 11 changed files with 166 additions and 22 deletions.
2 changes: 2 additions & 0 deletions libsolidity/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ set(sources
analysis/OverrideChecker.h
analysis/PostTypeChecker.cpp
analysis/PostTypeChecker.h
analysis/PostTypeContractLevelChecker.cpp
analysis/PostTypeContractLevelChecker.h
analysis/ReferencesResolver.cpp
analysis/ReferencesResolver.h
analysis/Scoper.cpp
Expand Down
18 changes: 0 additions & 18 deletions libsolidity/analysis/ContractLevelChecker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -433,24 +433,6 @@ void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contra
);
hashes.insert(hash);
}

map<uint32_t, SourceLocation> errorHashes;
for (ErrorDefinition const* error: _contract.interfaceErrors())
{
if (!error->functionType(true)->interfaceFunctionType())
// Will create an error later on.
continue;
uint32_t hash = selectorFromSignature32(error->functionType(true)->externalSignature());
if (errorHashes.count(hash))
m_errorReporter.typeError(
4883_error,
_contract.location(),
SecondarySourceLocation{}.append("This error has the same selector: ", errorHashes[hash]),
string("Error signature hash collision for ") + error->functionType(true)->externalSignature()
);
else
errorHashes[hash] = error->location();
}
}

void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
Expand Down
2 changes: 2 additions & 0 deletions libsolidity/analysis/FunctionCallGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,8 @@ bool FunctionCallGraphBuilder::visit(FunctionCall const& _functionCall)
// change at runtime). All we can do is to add an edge to the dispatch which in turn has
// edges to all functions could possibly be called.
add(m_currentNode, CallGraph::SpecialNode::InternalDispatch);
else if (functionType->kind() == FunctionType::Kind::Error)
m_graph.usedErrors.insert(&dynamic_cast<ErrorDefinition const&>(functionType->declaration()));

return true;
}
Expand Down
4 changes: 2 additions & 2 deletions libsolidity/analysis/FunctionCallGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,8 @@ class FunctionCallGraphBuilder: private ASTConstVisitor

private:
FunctionCallGraphBuilder(ContractDefinition const& _contract):
m_contract(_contract),
m_graph{{}, {}, {}} {}
m_contract(_contract)
{}

bool visit(FunctionCall const& _functionCall) override;
bool visit(EmitStatement const& _emitStatement) override;
Expand Down
70 changes: 70 additions & 0 deletions libsolidity/analysis/PostTypeContractLevelChecker.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Component that verifies overloads, abstract contracts, function clashes and others
* checks at contract or function level.
*/

#include <libsolidity/analysis/PostTypeContractLevelChecker.h>

#include <libsolidity/ast/AST.h>
#include <libsolutil/FunctionSelector.h>
#include <liblangutil/ErrorReporter.h>

using namespace std;
using namespace solidity;
using namespace solidity::langutil;
using namespace solidity::frontend;

bool PostTypeContractLevelChecker::check(SourceUnit const& _sourceUnit)
{
bool noErrors = true;
for (auto* contract: ASTNode::filteredNodes<ContractDefinition>(_sourceUnit.nodes()))
if (!check(*contract))
noErrors = false;
return noErrors;
}

bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
{
solAssert(
_contract.annotation().creationCallGraph.set() &&
_contract.annotation().deployedCallGraph.set(),
"" );

map<uint32_t, map<string, SourceLocation>> errorHashes;
for (ErrorDefinition const* error: _contract.interfaceErrors())
{
string signature = error->functionType(true)->externalSignature();
uint32_t hash = selectorFromSignature32(signature);
if (!errorHashes[hash].empty() && !errorHashes[hash].count(signature))
{
SourceLocation& otherLocation = errorHashes[hash].begin()->second;
m_errorReporter.typeError(
4883_error,
error->nameLocation(),
SecondarySourceLocation{}.append("This error has a different signature but the same hash: ", otherLocation),
string("Error signature hash collision for ") + error->functionType(true)->externalSignature()
);
}
else
errorHashes[hash][signature] = error->location();
}

return Error::containsOnlyWarnings(m_errorReporter.errors());
}
56 changes: 56 additions & 0 deletions libsolidity/analysis/PostTypeContractLevelChecker.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
/**
* Component that verifies properties at contract level, after the type checker has run.
*/

#pragma once

#include <libsolidity/ast/ASTForward.h>

namespace solidity::langutil
{
class ErrorReporter;
}

namespace solidity::frontend
{

/**
* Component that verifies properties at contract level, after the type checker has run.
*/
class PostTypeContractLevelChecker
{
public:
explicit PostTypeContractLevelChecker(langutil::ErrorReporter& _errorReporter):
m_errorReporter(_errorReporter)
{}

/// Performs checks on the given source ast.
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
bool check(SourceUnit const& _sourceUnit);

private:
/// Performs checks on the given contract.
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
bool check(ContractDefinition const& _contract);

langutil::ErrorReporter& m_errorReporter;
};

}
8 changes: 7 additions & 1 deletion libsolidity/ast/AST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@

#include <libsolidity/ast/AST.h>

#include <libsolidity/ast/CallGraph.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/AST_accept.h>
#include <libsolidity/ast/TypeProvider.h>
Expand Down Expand Up @@ -165,9 +166,14 @@ vector<EventDefinition const*> const& ContractDefinition::interfaceEvents() cons
vector<ErrorDefinition const*> ContractDefinition::interfaceErrors() const
{
set<ErrorDefinition const*, CompareByID> result;
// TODO add all referenced errors
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
result += filteredNodes<ErrorDefinition>(contract->m_subNodes);
solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set(), "");
if (annotation().creationCallGraph.set())
{
result += (*annotation().creationCallGraph)->usedErrors;
result += (*annotation().deployedCallGraph)->usedErrors;
}
return convertContainer<vector<ErrorDefinition const*>>(move(result));
}

Expand Down
3 changes: 3 additions & 0 deletions libsolidity/ast/CallGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ struct CallGraph

/// Events that may get emitted by functions present in the graph.
std::set<EventDefinition const*, ASTNode::CompareByID> emittedEvents;

/// Errors that are used by functions present in the graph.
std::set<ErrorDefinition const*, ASTNode::CompareByID> usedErrors;
};

}
9 changes: 9 additions & 0 deletions libsolidity/interface/CompilerStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include <libsolidity/analysis/GlobalContext.h>
#include <libsolidity/analysis/NameAndTypeResolver.h>
#include <libsolidity/analysis/PostTypeChecker.h>
#include <libsolidity/analysis/PostTypeContractLevelChecker.h>
#include <libsolidity/analysis/StaticAnalyzer.h>
#include <libsolidity/analysis/SyntaxChecker.h>
#include <libsolidity/analysis/Scoper.h>
Expand Down Expand Up @@ -433,6 +434,14 @@ bool CompilerStack::analyze()
noErrors = false;
}

if (noErrors)
{
for (Source const* source: m_sourceOrder)
if (source->ast && !PostTypeContractLevelChecker{m_errorReporter}.check(*source->ast))
noErrors = false;
}


// Check that immutable variables are never read in c'tors and assigned
// exactly once
if (noErrors)
Expand Down
2 changes: 1 addition & 1 deletion test/libsolidity/syntaxTests/errors/hash_collision.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ contract test {
error tgeo();
}
// ----
// TypeError 4883: (0-52): Error signature hash collision for tgeo()
// TypeError 4883: (43-47): Error signature hash collision for tgeo()
14 changes: 14 additions & 0 deletions test/libsolidity/syntaxTests/errors/hash_collision_external.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
library L {
error gsf();
}
contract test {
error tgeo();
function f(bool a) public {
if (a)
revert L.gsf();
else
revert tgeo();
}
}
// ----
// TypeError 4883: (57-61): Error signature hash collision for tgeo()

0 comments on commit 69d6b62

Please sign in to comment.