From 630fcc3a1dd6979c8c4635a0d8a9b8564582d477 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Tue, 1 Dec 2020 16:52:57 +0100 Subject: [PATCH] Define a comparator for InternalDispatchMap to ensure deterministic ordering of dispatch functions --- libsolidity/codegen/ir/IRGenerationContext.cpp | 10 ++++++++-- libsolidity/codegen/ir/IRGenerationContext.h | 17 +++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libsolidity/codegen/ir/IRGenerationContext.cpp b/libsolidity/codegen/ir/IRGenerationContext.cpp index eff854efd..99e5fb887 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.cpp +++ b/libsolidity/codegen/ir/IRGenerationContext.cpp @@ -128,7 +128,7 @@ void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _intern { solAssert(internalDispatchClean(), ""); - for (set const& functions: _internalDispatch | boost::adaptors::map_values) + for (DispatchSet const& functions: _internalDispatch | boost::adaptors::map_values) for (auto function: functions) enqueueFunctionForCodeGeneration(*function); @@ -147,7 +147,13 @@ void IRGenerationContext::addToInternalDispatch(FunctionDefinition const& _funct FunctionType const* functionType = TypeProvider::function(_function, FunctionType::Kind::Internal); solAssert(functionType, ""); - m_internalDispatchMap[YulArity::fromType(*functionType)].insert(&_function); + YulArity arity = YulArity::fromType(*functionType); + + if (m_internalDispatchMap.count(arity) != 0 && m_internalDispatchMap[arity].count(&_function) != 0) + // Note that m_internalDispatchMap[arity] is a set with a custom comparator, which looks at function IDs not definitions + solAssert(*m_internalDispatchMap[arity].find(&_function) == &_function, "Different definitions with the same function ID"); + + m_internalDispatchMap[arity].insert(&_function); enqueueFunctionForCodeGeneration(_function); } diff --git a/libsolidity/codegen/ir/IRGenerationContext.h b/libsolidity/codegen/ir/IRGenerationContext.h index 900bde7c5..3e9e96a54 100644 --- a/libsolidity/codegen/ir/IRGenerationContext.h +++ b/libsolidity/codegen/ir/IRGenerationContext.h @@ -44,7 +44,20 @@ namespace solidity::frontend class YulUtilFunctions; class ABIFunctions; -using InternalDispatchMap = std::map>; +struct AscendingFunctionIDCompare +{ + bool operator()(FunctionDefinition const* _f1, FunctionDefinition const* _f2) const + { + // NULLs always first. + if (_f1 != nullptr && _f2 != nullptr) + return _f1->id() < _f2->id(); + else + return _f1 == nullptr; + } +}; + +using DispatchSet = std::set; +using InternalDispatchMap = std::map; /** * Class that contains contextual information during IR generation. @@ -164,7 +177,7 @@ private: /// The order and duplicates are irrelevant here (hence std::set rather than std::queue) as /// long as the order of Yul functions in the generated code is deterministic and the same on /// all platforms - which is a property guaranteed by MultiUseYulFunctionCollector. - std::set m_functionGenerationQueue; + DispatchSet m_functionGenerationQueue; /// Collection of functions that need to be callable via internal dispatch. /// Note that having a key with an empty set of functions is a valid situation. It means that