diff options
author | chriseth <chris@ethereum.org> | 2018-12-18 18:36:58 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-12-18 18:36:58 +0800 |
commit | 4e475cdbe91e38e7b129248d4578b3a4fbf926be (patch) | |
tree | 5dbf391d521abb7e87338efe8da0d3129a19fbab /libsolidity/codegen | |
parent | 4b43aecaeb44651568f7d6590e41fdf3a497ff26 (diff) | |
parent | 1b8570f829ead5859c60e92e51e814e3baa50dc9 (diff) | |
download | dexon-solidity-4e475cdbe91e38e7b129248d4578b3a4fbf926be.tar.gz dexon-solidity-4e475cdbe91e38e7b129248d4578b3a4fbf926be.tar.zst dexon-solidity-4e475cdbe91e38e7b129248d4578b3a4fbf926be.zip |
Merge pull request #5625 from ethereum/single-check
Do check for callvalue only once if no payable functions
Diffstat (limited to 'libsolidity/codegen')
-rw-r--r-- | libsolidity/codegen/ContractCompiler.cpp | 51 |
1 files changed, 41 insertions, 10 deletions
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp index 16c90b60..b051d260 100644 --- a/libsolidity/codegen/ContractCompiler.cpp +++ b/libsolidity/codegen/ContractCompiler.cpp @@ -331,6 +331,25 @@ void ContractCompiler::appendInternalSelector( } } +namespace +{ + +// Helper function to check if any function is payable +bool hasPayableFunctions(ContractDefinition const& _contract) +{ + FunctionDefinition const* fallback = _contract.fallbackFunction(); + if (fallback && fallback->isPayable()) + return true; + + for (auto const& it: _contract.interfaceFunctions()) + if (it.second->isPayable()) + return true; + + return false; +} + +} + void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contract) { map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.interfaceFunctions(); @@ -342,6 +361,15 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac } FunctionDefinition const* fallback = _contract.fallbackFunction(); + solAssert(!_contract.isLibrary() || !fallback, "Libraries can't have fallback functions"); + + bool needToAddCallvalueCheck = true; + if (!hasPayableFunctions(_contract) && !interfaceFunctions.empty() && !_contract.isLibrary()) + { + appendCallValueCheck(); + needToAddCallvalueCheck = false; + } + eth::AssemblyItem notFound = m_context.newTag(); // directly jump to fallback if the data is too short to contain a function selector // also guards against short data @@ -350,23 +378,26 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac // retrieve the function signature hash from the calldata if (!interfaceFunctions.empty()) + { CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true); - // stack now is: <can-call-non-view-functions>? <funhash> - vector<FixedHash<4>> sortedIDs; - for (auto const& it: interfaceFunctions) - { - callDataUnpackerEntryPoints.insert(std::make_pair(it.first, m_context.newTag())); - sortedIDs.emplace_back(it.first); + // stack now is: <can-call-non-view-functions>? <funhash> + vector<FixedHash<4>> sortedIDs; + for (auto const& it: interfaceFunctions) + { + callDataUnpackerEntryPoints.emplace(it.first, m_context.newTag()); + sortedIDs.emplace_back(it.first); + } + std::sort(sortedIDs.begin(), sortedIDs.end()); + appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs); } - std::sort(sortedIDs.begin(), sortedIDs.end()); - appendInternalSelector(callDataUnpackerEntryPoints, sortedIDs, notFound, m_optimise_runs); m_context << notFound; + if (fallback) { solAssert(!_contract.isLibrary(), ""); - if (!fallback->isPayable()) + if (!fallback->isPayable() && needToAddCallvalueCheck) appendCallValueCheck(); solAssert(fallback->isFallback(), ""); @@ -396,7 +427,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac m_context.setStackOffset(0); // We have to allow this for libraries, because value of the previous // call is still visible in the delegatecall. - if (!functionType->isPayable() && !_contract.isLibrary()) + if (!functionType->isPayable() && !_contract.isLibrary() && needToAddCallvalueCheck) appendCallValueCheck(); // Return tag is used to jump out of the function. |