From 5e01d767d02d064a064a67dcf95ee299c46f741f Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 17 Jan 2018 12:05:43 +0100 Subject: Prevent externally used functions from being removed. --- libsolidity/codegen/ABIFunctions.cpp | 15 +++++++++++---- libsolidity/codegen/ABIFunctions.h | 15 ++++++++++++--- libsolidity/codegen/CompilerContext.cpp | 1 + libsolidity/codegen/CompilerContext.h | 2 ++ libsolidity/codegen/ContractCompiler.cpp | 6 +++--- libyul/optimiser/UnusedPruner.cpp | 8 +++++--- libyul/optimiser/UnusedPruner.h | 4 ++-- 7 files changed, 36 insertions(+), 15 deletions(-) diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp index 6c27533c..bd29b382 100644 --- a/libsolidity/codegen/ABIFunctions.cpp +++ b/libsolidity/codegen/ABIFunctions.cpp @@ -49,7 +49,7 @@ string ABIFunctions::tupleEncoder( if (_encodeAsLibraryTypes) functionName += "_library"; - return createFunction(functionName, [&]() { + return createExternallyUsedFunction(functionName, [&]() { solAssert(!_givenTypes.empty(), ""); // Note that the values are in reverse due to the difference in calling semantics. @@ -113,7 +113,7 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) solAssert(!_types.empty(), ""); - return createFunction(functionName, [&]() { + return createExternallyUsedFunction(functionName, [&]() { TypePointers decodingTypes; for (auto const& t: _types) decodingTypes.emplace_back(t->decodingType()); @@ -176,13 +176,13 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) }); } -string ABIFunctions::requestedFunctions() +pair> ABIFunctions::requestedFunctions() { string result; for (auto const& f: m_requestedFunctions) result += f.second; m_requestedFunctions.clear(); - return result; + return make_pair(result, std::move(m_externallyUsedFunctions)); } string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) @@ -1697,6 +1697,13 @@ string ABIFunctions::createFunction(string const& _name, function con return _name; } +string ABIFunctions::createExternallyUsedFunction(string const& _name, function const& _creator) +{ + string name = createFunction(_name, _creator); + m_externallyUsedFunctions.insert(name); + return name; +} + size_t ABIFunctions::headSize(TypePointers const& _targetTypes) { size_t headSize = 0; diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h index 3caaa1d9..e9ffe4fb 100644 --- a/libsolidity/codegen/ABIFunctions.h +++ b/libsolidity/codegen/ABIFunctions.h @@ -28,6 +28,7 @@ #include #include +#include #include namespace dev { @@ -80,8 +81,11 @@ public: /// stack slot, it takes exactly that number of values. std::string tupleDecoder(TypePointers const& _types, bool _fromMemory = false); - /// @returns concatenation of all generated functions. - std::string requestedFunctions(); + /// @returns concatenation of all generated functions and a set of the + /// externally used functions. + /// Clears the internal list, i.e. calling it again will result in an + /// empty return value. + std::pair> requestedFunctions(); private: /// @returns the name of the cleanup function for the given type and @@ -224,12 +228,17 @@ private: /// cases. std::string createFunction(std::string const& _name, std::function const& _creator); + /// Helper function that uses @a _creator to create a function and add it to + /// @a m_requestedFunctions if it has not been created yet and returns @a _name in both + /// cases. Also adds it to the list of externally used functions. + std::string createExternallyUsedFunction(std::string const& _name, std::function const& _creator); + /// @returns the size of the static part of the encoding of the given types. static size_t headSize(TypePointers const& _targetTypes); /// Map from function name to code for a multi-use function. std::map m_requestedFunctions; - + std::set m_externallyUsedFunctions; EVMVersion m_evmVersion; }; diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp index 089386b5..210b613d 100644 --- a/libsolidity/codegen/CompilerContext.cpp +++ b/libsolidity/codegen/CompilerContext.cpp @@ -313,6 +313,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node) void CompilerContext::appendInlineAssembly( string const& _assembly, vector const& _localVariables, + set const&, bool _system ) { diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h index 3f357821..5bdc1d19 100644 --- a/libsolidity/codegen/CompilerContext.h +++ b/libsolidity/codegen/CompilerContext.h @@ -206,10 +206,12 @@ public: /// Appends inline assembly (strict mode). /// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly. /// @param _localVariables assigns stack positions to variables with the last one being the stack top + /// @param _externallyUsedFunctions a set of function names that are not to be renamed or removed. /// @param _system if true, this is a "system-level" assembly where all functions use named labels. void appendInlineAssembly( std::string const& _assembly, std::vector const& _localVariables = std::vector(), + std::set const& _externallyUsedFunctions = std::set(), bool _system = false ); diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index c845da8f..1fdf3483 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -874,9 +874,9 @@ void ContractCompiler::appendMissingFunctions() solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?"); } m_context.appendMissingLowLevelFunctions(); - string abiFunctions = m_context.abiFunctions().requestedFunctions(); - if (!abiFunctions.empty()) - m_context.appendInlineAssembly("{" + move(abiFunctions) + "}", {}, true); + auto abiFunctions = m_context.abiFunctions().requestedFunctions(); + if (!abiFunctions.first.empty()) + m_context.appendInlineAssembly("{" + move(abiFunctions.first) + "}", {}, abiFunctions.second, true); } void ContractCompiler::appendModifierOrFunctionCode() diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp index 74b6bee4..37a74553 100644 --- a/libyul/optimiser/UnusedPruner.cpp +++ b/libyul/optimiser/UnusedPruner.cpp @@ -33,12 +33,14 @@ using namespace std; using namespace dev; using namespace dev::yul; -UnusedPruner::UnusedPruner(Block& _ast) +UnusedPruner::UnusedPruner(Block& _ast, set const& _externallyUsedFunctions) { ReferencesCounter counter; counter(_ast); m_references = counter.references(); + for (auto const& f: _externallyUsedFunctions) + ++m_references[f]; } void UnusedPruner::operator()(Block& _block) @@ -89,11 +91,11 @@ void UnusedPruner::operator()(Block& _block) ASTModifier::operator()(_block); } -void UnusedPruner::runUntilStabilised(Block& _ast) +void UnusedPruner::runUntilStabilised(Block& _ast, set const& _externallyUsedFunctions) { while (true) { - UnusedPruner pruner(_ast); + UnusedPruner pruner(_ast, _externallyUsedFunctions); pruner(_ast); if (!pruner.shouldRunAgain()) return; diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h index 327921ea..30617ff3 100644 --- a/libyul/optimiser/UnusedPruner.h +++ b/libyul/optimiser/UnusedPruner.h @@ -44,7 +44,7 @@ namespace yul class UnusedPruner: public ASTModifier { public: - explicit UnusedPruner(Block& _ast); + explicit UnusedPruner(Block& _ast, std::set const& _externallyUsedFunctions = std::set()); using ASTModifier::operator(); virtual void operator()(Block& _block) override; @@ -53,7 +53,7 @@ public: bool shouldRunAgain() const { return m_shouldRunAgain; } // Run the pruner until the code does not change anymore. - static void runUntilStabilised(Block& _ast); + static void runUntilStabilised(Block& _ast, std::set const& _externallyUsedFunctions = std::set()); private: bool used(std::string const& _name) const; -- cgit v1.2.3 From 16c2a775fd532c301eae3abecc8d68c5c421a9a0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Fri, 19 Jan 2018 17:23:49 +0100 Subject: Handle externally supplied variables correctly in disambiguator. --- libyul/optimiser/Disambiguator.cpp | 3 +++ libyul/optimiser/Disambiguator.h | 12 +++++++++--- test/libyul/Common.cpp | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/libyul/optimiser/Disambiguator.cpp b/libyul/optimiser/Disambiguator.cpp index af3507e1..dcba97c9 100644 --- a/libyul/optimiser/Disambiguator.cpp +++ b/libyul/optimiser/Disambiguator.cpp @@ -34,6 +34,9 @@ using Scope = dev::solidity::assembly::Scope; string Disambiguator::translateIdentifier(string const& _originalName) { + if ((m_externallyUsedIdentifiers.count(_originalName))) + return _originalName; + assertThrow(!m_scopes.empty() && m_scopes.back(), OptimizerException, ""); Scope::Identifier const* id = m_scopes.back()->lookup(_originalName); assertThrow(id, OptimizerException, ""); diff --git a/libyul/optimiser/Disambiguator.h b/libyul/optimiser/Disambiguator.h index 0829fd58..e16ebfbf 100644 --- a/libyul/optimiser/Disambiguator.h +++ b/libyul/optimiser/Disambiguator.h @@ -43,9 +43,14 @@ namespace yul class Disambiguator: public ASTCopier { public: - Disambiguator(solidity::assembly::AsmAnalysisInfo const& _analysisInfo): - m_info(_analysisInfo) - {} + explicit Disambiguator( + solidity::assembly::AsmAnalysisInfo const& _analysisInfo, + std::set const& _externallyUsedIdentifiers = {} + ): + m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers) + { + m_nameDispenser.m_usedNames = m_externallyUsedIdentifiers; + } protected: virtual void enterScope(Block const& _block) override; @@ -58,6 +63,7 @@ protected: void leaveScopeInternal(solidity::assembly::Scope& _scope); solidity::assembly::AsmAnalysisInfo const& m_info; + std::set const& m_externallyUsedIdentifiers; std::vector m_scopes; std::map m_translations; diff --git a/test/libyul/Common.cpp b/test/libyul/Common.cpp index 4c50180a..d224bdcd 100644 --- a/test/libyul/Common.cpp +++ b/test/libyul/Common.cpp @@ -86,7 +86,7 @@ pair, shared_ptr> dev::yul::test::p assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul) { auto result = parse(_source, _yul); - return boost::get(Disambiguator(*result.second)(*result.first)); + return boost::get(Disambiguator(*result.second, {})(*result.first)); } string dev::yul::test::format(string const& _source, bool _yul) -- cgit v1.2.3