aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/codegen/ExpressionCompiler.cpp
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2016-08-08 01:40:19 +0800
committerchriseth <c@ethdev.com>2016-08-16 20:53:01 +0800
commit034d436933806c204b84b0500e2116938cb6a030 (patch)
tree03c6d183fc5358a56a271df9f2587f3918929cba /libsolidity/codegen/ExpressionCompiler.cpp
parente3e4d84f3353eaaaadae7c1c6eac9e890188d0f8 (diff)
downloaddexon-solidity-034d436933806c204b84b0500e2116938cb6a030.tar.gz
dexon-solidity-034d436933806c204b84b0500e2116938cb6a030.tar.zst
dexon-solidity-034d436933806c204b84b0500e2116938cb6a030.zip
Make ecrecover throw for malformed input.
Diffstat (limited to 'libsolidity/codegen/ExpressionCompiler.cpp')
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp45
1 files changed, 40 insertions, 5 deletions
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 1d574556..50148901 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -1445,6 +1445,19 @@ void ExpressionCompiler::appendExternalFunctionCall(
argumentTypes.push_back(_arguments[i]->annotation().type);
}
+ if (funKind == FunctionKind::ECRecover)
+ {
+ // Clears 32 bytes of currently free memory and advances free memory pointer.
+ // Output area will be "start of input area" - 32.
+ // The reason is that a failing ECRecover cannot be detected, it will just return
+ // zero bytes (which we cannot detect).
+ solAssert(0 < retSize && retSize <= 32, "");
+ utils().fetchFreeMemoryPointer();
+ m_context << Instruction::DUP1 << u256(0) << Instruction::MSTORE;
+ m_context << u256(32) << Instruction::ADD;
+ utils().storeFreeMemoryPointer();
+ }
+
// Copy function identifier to memory.
utils().fetchFreeMemoryPointer();
if (!_functionType.isBareCall() || manualFunctionId)
@@ -1453,7 +1466,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
}
// If the function takes arbitrary parameters, copy dynamic length data in place.
- // Move argumenst to memory, will not update the free memory pointer (but will update the memory
+ // Move arguments to memory, will not update the free memory pointer (but will update the memory
// pointer on the stack).
utils().encodeToMemory(
argumentTypes,
@@ -1471,12 +1484,24 @@ void ExpressionCompiler::appendExternalFunctionCall(
// function identifier [unless bare]
// contract address
- // Output data will replace input data.
+ // Output data will replace input data, unless we have ECRecover (then, output
+ // area will be 32 bytes just before input area).
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
m_context << u256(retSize);
- utils().fetchFreeMemoryPointer();
- m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB;
- m_context << Instruction::DUP2;
+ utils().fetchFreeMemoryPointer(); // This is the start of input
+ if (funKind == FunctionKind::ECRecover)
+ {
+ // In this case, output is 32 bytes before input and has already been cleared.
+ m_context << u256(32) << Instruction::DUP2 << Instruction::SUB << Instruction::SWAP1;
+ // Here: <input end> <output size> <outpos> <input pos>
+ m_context << Instruction::DUP1 << Instruction::DUP5 << Instruction::SUB;
+ m_context << Instruction::SWAP1;
+ }
+ else
+ {
+ m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB;
+ m_context << Instruction::DUP2;
+ }
// CALL arguments: outSize, outOff, inSize, inOff (already present up to here)
// [value,] addr, gas (stack top)
@@ -1539,6 +1564,16 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().loadFromMemoryDynamic(IntegerType(160), false, true, false);
utils().convertType(IntegerType(160), FixedBytesType(20));
}
+ else if (funKind == FunctionKind::ECRecover)
+ {
+ // Output is 32 bytes before input / free mem pointer.
+ // Failing ecrecover cannot be detected, so we clear output before the call.
+ m_context << u256(32);
+ utils().fetchFreeMemoryPointer();
+ m_context << Instruction::SUB << Instruction::MLOAD;
+ m_context << Instruction::DUP1 << Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(m_context.errorTag());
+ }
else if (!_functionType.returnParameterTypes().empty())
{
utils().fetchFreeMemoryPointer();