aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md1
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp7
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp20
3 files changed, 27 insertions, 1 deletions
diff --git a/Changelog.md b/Changelog.md
index 27f88cd2..c9a830dc 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -42,6 +42,7 @@ Bugfixes:
* Why3 translator: crash fix for exponentiation
* Type Checker: Fallback function cannot return data anymore.
* Code Generator: Fix crash when sha3() was used on unsupported types.
+ * Code Generator: Manually set gas stipend for .send(0).
Lots of changes to the documentation mainly by voluntary external contributors.
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 1cc4a50d..96ca4296 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -568,12 +568,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
case Location::Send:
_functionCall.expression().accept(*this);
- m_context << u256(0); // do not send gas (there still is the stipend)
+ // Provide the gas stipend manually at first because we may send zero ether.
+ // Will be zeroed if we send more than zero ether.
+ m_context << u256(eth::GasCosts::callStipend);
arguments.front()->accept(*this);
utils().convertType(
*arguments.front()->annotation().type,
*function.parameterTypes().front(), true
);
+ // gas <- gas * !value
+ m_context << Instruction::SWAP1 << Instruction::DUP2;
+ m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
appendExternalFunctionCall(
FunctionType(
TypePointers{},
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 1ecd7a2c..3c85d8a8 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -4625,6 +4625,26 @@ BOOST_AUTO_TEST_CASE(failing_send)
BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20));
}
+BOOST_AUTO_TEST_CASE(send_zero_ether)
+{
+ // Sending zero ether to a contract should still invoke the fallback function
+ // (it previously did not because the gas stipend was not provided by the EVM)
+ char const* sourceCode = R"(
+ contract Receiver {
+ function () payable {
+ }
+ }
+ contract Main {
+ function s() returns (bool) {
+ var r = new Receiver();
+ return r.send(0);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 20, "Main");
+ BOOST_REQUIRE(callContractFunction("s()") == encodeArgs(true));
+}
+
BOOST_AUTO_TEST_CASE(reusing_memory)
{
// Invoke some features that use memory and test that they do not interfere with each other.