Merge pull request #5227 from ethereum/doNotRemoveExternallyUsedFunction

Prevent externally used functions from being removed.
This commit is contained in:
chriseth 2018-10-17 17:05:49 +02:00 committed by GitHub
commit f2f72ff7ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 49 additions and 19 deletions

View File

@ -49,7 +49,7 @@ string ABIFunctions::tupleEncoder(
if (_encodeAsLibraryTypes) if (_encodeAsLibraryTypes)
functionName += "_library"; functionName += "_library";
return createFunction(functionName, [&]() { return createExternallyUsedFunction(functionName, [&]() {
solAssert(!_givenTypes.empty(), ""); solAssert(!_givenTypes.empty(), "");
// Note that the values are in reverse due to the difference in calling semantics. // 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(), ""); solAssert(!_types.empty(), "");
return createFunction(functionName, [&]() { return createExternallyUsedFunction(functionName, [&]() {
TypePointers decodingTypes; TypePointers decodingTypes;
for (auto const& t: _types) for (auto const& t: _types)
decodingTypes.emplace_back(t->decodingType()); decodingTypes.emplace_back(t->decodingType());
@ -176,13 +176,13 @@ string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory)
}); });
} }
string ABIFunctions::requestedFunctions() pair<string, set<string>> ABIFunctions::requestedFunctions()
{ {
string result; string result;
for (auto const& f: m_requestedFunctions) for (auto const& f: m_requestedFunctions)
result += f.second; result += f.second;
m_requestedFunctions.clear(); m_requestedFunctions.clear();
return result; return make_pair(result, std::move(m_externallyUsedFunctions));
} }
string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure) string ABIFunctions::cleanupFunction(Type const& _type, bool _revertOnFailure)
@ -1697,6 +1697,13 @@ string ABIFunctions::createFunction(string const& _name, function<string ()> con
return _name; return _name;
} }
string ABIFunctions::createExternallyUsedFunction(string const& _name, function<string ()> const& _creator)
{
string name = createFunction(_name, _creator);
m_externallyUsedFunctions.insert(name);
return name;
}
size_t ABIFunctions::headSize(TypePointers const& _targetTypes) size_t ABIFunctions::headSize(TypePointers const& _targetTypes)
{ {
size_t headSize = 0; size_t headSize = 0;

View File

@ -28,6 +28,7 @@
#include <vector> #include <vector>
#include <functional> #include <functional>
#include <set>
#include <map> #include <map>
namespace dev { namespace dev {
@ -80,8 +81,11 @@ public:
/// stack slot, it takes exactly that number of values. /// stack slot, it takes exactly that number of values.
std::string tupleDecoder(TypePointers const& _types, bool _fromMemory = false); std::string tupleDecoder(TypePointers const& _types, bool _fromMemory = false);
/// @returns concatenation of all generated functions. /// @returns concatenation of all generated functions and a set of the
std::string requestedFunctions(); /// externally used functions.
/// Clears the internal list, i.e. calling it again will result in an
/// empty return value.
std::pair<std::string, std::set<std::string>> requestedFunctions();
private: private:
/// @returns the name of the cleanup function for the given type and /// @returns the name of the cleanup function for the given type and
@ -224,12 +228,17 @@ private:
/// cases. /// cases.
std::string createFunction(std::string const& _name, std::function<std::string()> const& _creator); std::string createFunction(std::string const& _name, std::function<std::string()> 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<std::string()> const& _creator);
/// @returns the size of the static part of the encoding of the given types. /// @returns the size of the static part of the encoding of the given types.
static size_t headSize(TypePointers const& _targetTypes); static size_t headSize(TypePointers const& _targetTypes);
/// Map from function name to code for a multi-use function. /// Map from function name to code for a multi-use function.
std::map<std::string, std::string> m_requestedFunctions; std::map<std::string, std::string> m_requestedFunctions;
std::set<std::string> m_externallyUsedFunctions;
EVMVersion m_evmVersion; EVMVersion m_evmVersion;
}; };

View File

@ -313,6 +313,7 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
void CompilerContext::appendInlineAssembly( void CompilerContext::appendInlineAssembly(
string const& _assembly, string const& _assembly,
vector<string> const& _localVariables, vector<string> const& _localVariables,
set<string> const&,
bool _system bool _system
) )
{ {

View File

@ -206,10 +206,12 @@ public:
/// Appends inline assembly (strict mode). /// Appends inline assembly (strict mode).
/// @a _replacements are string-matching replacements that are performed prior to parsing the inline assembly. /// @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 _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. /// @param _system if true, this is a "system-level" assembly where all functions use named labels.
void appendInlineAssembly( void appendInlineAssembly(
std::string const& _assembly, std::string const& _assembly,
std::vector<std::string> const& _localVariables = std::vector<std::string>(), std::vector<std::string> const& _localVariables = std::vector<std::string>(),
std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>(),
bool _system = false bool _system = false
); );

View File

@ -874,9 +874,9 @@ void ContractCompiler::appendMissingFunctions()
solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?"); solAssert(m_context.nextFunctionToCompile() != function, "Compiled the wrong function?");
} }
m_context.appendMissingLowLevelFunctions(); m_context.appendMissingLowLevelFunctions();
string abiFunctions = m_context.abiFunctions().requestedFunctions(); auto abiFunctions = m_context.abiFunctions().requestedFunctions();
if (!abiFunctions.empty()) if (!abiFunctions.first.empty())
m_context.appendInlineAssembly("{" + move(abiFunctions) + "}", {}, true); m_context.appendInlineAssembly("{" + move(abiFunctions.first) + "}", {}, abiFunctions.second, true);
} }
void ContractCompiler::appendModifierOrFunctionCode() void ContractCompiler::appendModifierOrFunctionCode()

View File

@ -34,6 +34,9 @@ using Scope = dev::solidity::assembly::Scope;
string Disambiguator::translateIdentifier(string const& _originalName) string Disambiguator::translateIdentifier(string const& _originalName)
{ {
if ((m_externallyUsedIdentifiers.count(_originalName)))
return _originalName;
assertThrow(!m_scopes.empty() && m_scopes.back(), OptimizerException, ""); assertThrow(!m_scopes.empty() && m_scopes.back(), OptimizerException, "");
Scope::Identifier const* id = m_scopes.back()->lookup(_originalName); Scope::Identifier const* id = m_scopes.back()->lookup(_originalName);
assertThrow(id, OptimizerException, ""); assertThrow(id, OptimizerException, "");

View File

@ -43,9 +43,14 @@ namespace yul
class Disambiguator: public ASTCopier class Disambiguator: public ASTCopier
{ {
public: public:
Disambiguator(solidity::assembly::AsmAnalysisInfo const& _analysisInfo): explicit Disambiguator(
m_info(_analysisInfo) solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
{} std::set<std::string> const& _externallyUsedIdentifiers = {}
):
m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers)
{
m_nameDispenser.m_usedNames = m_externallyUsedIdentifiers;
}
protected: protected:
virtual void enterScope(Block const& _block) override; virtual void enterScope(Block const& _block) override;
@ -58,6 +63,7 @@ protected:
void leaveScopeInternal(solidity::assembly::Scope& _scope); void leaveScopeInternal(solidity::assembly::Scope& _scope);
solidity::assembly::AsmAnalysisInfo const& m_info; solidity::assembly::AsmAnalysisInfo const& m_info;
std::set<std::string> const& m_externallyUsedIdentifiers;
std::vector<solidity::assembly::Scope*> m_scopes; std::vector<solidity::assembly::Scope*> m_scopes;
std::map<void const*, std::string> m_translations; std::map<void const*, std::string> m_translations;

View File

@ -33,12 +33,14 @@ using namespace std;
using namespace dev; using namespace dev;
using namespace dev::yul; using namespace dev::yul;
UnusedPruner::UnusedPruner(Block& _ast) UnusedPruner::UnusedPruner(Block& _ast, set<string> const& _externallyUsedFunctions)
{ {
ReferencesCounter counter; ReferencesCounter counter;
counter(_ast); counter(_ast);
m_references = counter.references(); m_references = counter.references();
for (auto const& f: _externallyUsedFunctions)
++m_references[f];
} }
void UnusedPruner::operator()(Block& _block) void UnusedPruner::operator()(Block& _block)
@ -89,11 +91,11 @@ void UnusedPruner::operator()(Block& _block)
ASTModifier::operator()(_block); ASTModifier::operator()(_block);
} }
void UnusedPruner::runUntilStabilised(Block& _ast) void UnusedPruner::runUntilStabilised(Block& _ast, set<string> const& _externallyUsedFunctions)
{ {
while (true) while (true)
{ {
UnusedPruner pruner(_ast); UnusedPruner pruner(_ast, _externallyUsedFunctions);
pruner(_ast); pruner(_ast);
if (!pruner.shouldRunAgain()) if (!pruner.shouldRunAgain())
return; return;

View File

@ -44,7 +44,7 @@ namespace yul
class UnusedPruner: public ASTModifier class UnusedPruner: public ASTModifier
{ {
public: public:
explicit UnusedPruner(Block& _ast); explicit UnusedPruner(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
using ASTModifier::operator(); using ASTModifier::operator();
virtual void operator()(Block& _block) override; virtual void operator()(Block& _block) override;
@ -53,7 +53,7 @@ public:
bool shouldRunAgain() const { return m_shouldRunAgain; } bool shouldRunAgain() const { return m_shouldRunAgain; }
// Run the pruner until the code does not change anymore. // Run the pruner until the code does not change anymore.
static void runUntilStabilised(Block& _ast); static void runUntilStabilised(Block& _ast, std::set<std::string> const& _externallyUsedFunctions = std::set<std::string>());
private: private:
bool used(std::string const& _name) const; bool used(std::string const& _name) const;

View File

@ -86,7 +86,7 @@ pair<shared_ptr<Block>, shared_ptr<assembly::AsmAnalysisInfo>> dev::yul::test::p
assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul) assembly::Block dev::yul::test::disambiguate(string const& _source, bool _yul)
{ {
auto result = parse(_source, _yul); auto result = parse(_source, _yul);
return boost::get<Block>(Disambiguator(*result.second)(*result.first)); return boost::get<Block>(Disambiguator(*result.second, {})(*result.first));
} }
string dev::yul::test::format(string const& _source, bool _yul) string dev::yul::test::format(string const& _source, bool _yul)