diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index d171006a8..ea8ecdb75 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -50,18 +50,27 @@ void ContractDefinition::checkTypeRequirements() for (ASTPointer const& function: getDefinedFunctions()) function->checkTypeRequirements(); + + // check for hash collisions in function signatures + vector, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList(); + set> hashes; + for (auto const& hashAndFunction: getInterfaceFunctionList()) + { + FixedHash<4> const& hash = hashAndFunction.first; + if (hashes.count(hash)) + BOOST_THROW_EXCEPTION(createTypeError("Function signature hash collision for " + + hashAndFunction.second->getCanonicalSignature())); + hashes.insert(hash); + } } map, FunctionDefinition const*> ContractDefinition::getInterfaceFunctions() const { - map, FunctionDefinition const*> exportedFunctions; - for (ASTPointer const& f: m_definedFunctions) - if (f->isPublic() && f->getName() != getName()) - { - FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); - auto res = exportedFunctions.insert(std::make_pair(hash,f.get())); - solAssert(res.second, "Hash collision at Function Definition Hash calculation"); - } + vector, FunctionDefinition const*>> exportedFunctionList = getInterfaceFunctionList(); + map, FunctionDefinition const*> exportedFunctions(exportedFunctionList.begin(), + exportedFunctionList.end()); + solAssert(exportedFunctionList.size() == exportedFunctions.size(), + "Hash collision at Function Definition Hash calculation"); return exportedFunctions; } @@ -74,6 +83,19 @@ FunctionDefinition const* ContractDefinition::getConstructor() const return nullptr; } +vector, FunctionDefinition const*>> ContractDefinition::getInterfaceFunctionList() const +{ + vector, FunctionDefinition const*>> exportedFunctions; + for (ASTPointer const& f: m_definedFunctions) + if (f->isPublic() && f->getName() != getName()) + { + FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); + exportedFunctions.push_back(make_pair(hash, f.get())); + } + + return exportedFunctions; +} + void StructDefinition::checkMemberTypes() const { for (ASTPointer const& member: getMembers()) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 95121d4cb..28fb7f0a5 100755 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -191,6 +191,8 @@ public: FunctionDefinition const* getConstructor() const; private: + std::vector, FunctionDefinition const*>> getInterfaceFunctionList() const; + std::vector> m_definedStructs; std::vector> m_stateVariables; std::vector> m_definedFunctions; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 94271b1f7..e2b4f160d 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -357,6 +357,18 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases) } } + +BOOST_AUTO_TEST_CASE(hash_collision_in_interface) +{ + char const* text = "contract test {\n" + " function gsf() {\n" + " }\n" + " function tgeo() {\n" + " }\n" + "}\n"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_SUITE_END() }