aboutsummaryrefslogtreecommitdiffstats
path: root/Compiler.cpp
diff options
context:
space:
mode:
authorChristian <c@ethdev.com>2014-11-10 20:13:40 +0800
committerChristian <c@ethdev.com>2014-11-10 20:13:53 +0800
commit41b26e491b9a4eaa1ef481e7e57ebc1111315033 (patch)
tree8426f5fbd902794f7de7f26576b62aa78928cd2c /Compiler.cpp
parentd9822190c6fb3ac5025296c0f47977cca9547b91 (diff)
downloaddexon-solidity-41b26e491b9a4eaa1ef481e7e57ebc1111315033.tar.gz
dexon-solidity-41b26e491b9a4eaa1ef481e7e57ebc1111315033.tar.zst
dexon-solidity-41b26e491b9a4eaa1ef481e7e57ebc1111315033.zip
Replace function selector jump table by more resilient linear time check.
Diffstat (limited to 'Compiler.cpp')
-rw-r--r--Compiler.cpp39
1 files changed, 19 insertions, 20 deletions
diff --git a/Compiler.cpp b/Compiler.cpp
index ce87f7bb..c5e25a12 100644
--- a/Compiler.cpp
+++ b/Compiler.cpp
@@ -81,35 +81,34 @@ void Compiler::appendFunctionSelector(vector<ASTPointer<FunctionDefinition>> con
if (publicFunctions.size() > 255)
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("More than 255 public functions for contract."));
- //@todo check for calldatasize?
- // retrieve the first byte of the call data
- m_context << u256(0) << eth::Instruction::CALLDATALOAD << u256(0) << eth::Instruction::BYTE;
- // check that it is not too large
- m_context << eth::Instruction::DUP1 << u256(publicFunctions.size() - 1) << eth::Instruction::LT;
- eth::AssemblyItem returnTag = m_context.appendConditionalJump();
-
- // otherwise, jump inside jump table (each entry of the table has size 4)
- m_context << u256(4) << eth::Instruction::MUL;
- eth::AssemblyItem jumpTableStart = m_context.pushNewTag();
- m_context << eth::Instruction::ADD << eth::Instruction::JUMP;
-
- // jump table @todo it could be that the optimizer destroys this
- m_context << jumpTableStart;
+ // retrieve the first byte of the call data, which determines the called function
+ // @todo This code had a jump table in a previous version which was more efficient but also
+ // error prone (due to the optimizer and variable length tag addresses)
+ m_context << u256(1) << u256(0) // some constants
+ << eth::dupInstruction(1) << eth::Instruction::CALLDATALOAD
+ << eth::dupInstruction(2) << eth::Instruction::BYTE
+ << eth::dupInstruction(2);
+
+ // stack here: 1 0 <funid> 0, stack top will be counted up until it matches funid
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
- m_context.appendJumpTo(f.second.second) << eth::Instruction::JUMPDEST;
-
- m_context << returnTag << eth::Instruction::STOP;
+ {
+ eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
+ m_context << eth::dupInstruction(2) << eth::dupInstruction(2) << eth::Instruction::EQ;
+ m_context.appendConditionalJumpTo(callDataUnpackerEntry);
+ m_context << eth::dupInstruction(4) << eth::Instruction::ADD;
+ //@todo avoid the last ADD (or remove it in the optimizer)
+ }
+ m_context << eth::Instruction::STOP; // function not found
for (pair<string, pair<FunctionDefinition const*, eth::AssemblyItem>> const& f: publicFunctions)
{
FunctionDefinition const& function = *f.second.first;
- m_context << f.second.second;
-
+ eth::AssemblyItem const& callDataUnpackerEntry = f.second.second;
+ m_context << callDataUnpackerEntry;
eth::AssemblyItem returnTag = m_context.pushNewTag();
appendCalldataUnpacker(function);
m_context.appendJumpTo(m_context.getFunctionEntryLabel(function));
m_context << returnTag;
-
appendReturnValuePacker(function);
}
}