aboutsummaryrefslogtreecommitdiffstats
path: root/test/libsolidity/SolidityEndToEndTest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/libsolidity/SolidityEndToEndTest.cpp')
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp230
1 files changed, 226 insertions, 4 deletions
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 1b7c5ea4..4e6f68b0 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2390,7 +2390,8 @@ BOOST_AUTO_TEST_CASE(function_modifier_multi_invocation)
BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return)
{
- // Here, the explicit return prevents the second execution
+ // Note that return sets the return variable and jumps to the end of the current function or
+ // modifier code block.
char const* sourceCode = R"(
contract C {
modifier repeat(bool twice) { if (twice) _ _ }
@@ -2399,7 +2400,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_multi_with_return)
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("f(bool)", false) == encodeArgs(1));
- BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(1));
+ BOOST_CHECK(callContractFunction("f(bool)", true) == encodeArgs(2));
}
BOOST_AUTO_TEST_CASE(function_modifier_overriding)
@@ -2410,7 +2411,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_overriding)
modifier mod { _ }
}
contract C is A {
- modifier mod { }
+ modifier mod { if (false) _ }
}
)";
compileAndRun(sourceCode);
@@ -2427,7 +2428,7 @@ BOOST_AUTO_TEST_CASE(function_modifier_calling_functions_in_creation_context)
function f2() { data |= 0x20; }
function f3() { }
modifier mod1 { f2(); _ }
- modifier mod2 { f3(); }
+ modifier mod2 { f3(); if (false) _ }
function getData() returns (uint r) { return data; }
}
contract C is A {
@@ -6208,6 +6209,27 @@ BOOST_AUTO_TEST_CASE(addmod_mulmod)
BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(0)));
}
+BOOST_AUTO_TEST_CASE(divisiod_by_zero)
+{
+ char const* sourceCode = R"(
+ contract C {
+ function div(uint a, uint b) returns (uint) {
+ return a / b;
+ }
+ function mod(uint a, uint b) returns (uint) {
+ return a % b;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+ BOOST_CHECK(callContractFunction("div(uint256,uint256)", 7, 2) == encodeArgs(u256(3)));
+ // throws
+ BOOST_CHECK(callContractFunction("div(uint256,uint256)", 7, 0) == encodeArgs());
+ BOOST_CHECK(callContractFunction("mod(uint256,uint256)", 7, 2) == encodeArgs(u256(1)));
+ // throws
+ BOOST_CHECK(callContractFunction("mod(uint256,uint256)", 7, 0) == encodeArgs());
+}
+
BOOST_AUTO_TEST_CASE(string_allocation_bug)
{
char const* sourceCode = R"(
@@ -6839,6 +6861,33 @@ BOOST_AUTO_TEST_CASE(skip_dynamic_types_for_structs)
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(2), u256(6)));
}
+BOOST_AUTO_TEST_CASE(failed_create)
+{
+ char const* sourceCode = R"(
+ contract D { }
+ contract C {
+ uint public x;
+ function f(uint amount) returns (address) {
+ x++;
+ return (new D).value(amount)();
+ }
+ function stack(uint depth) returns (address) {
+ if (depth < 1024)
+ return this.stack(depth - 1);
+ else
+ return f(0);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 20, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", 20) != encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256)", 20) == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("stack(uint256)", 1023) == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+}
+
BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length)
{
char const* sourceCode = R"(
@@ -6853,6 +6902,179 @@ BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
}
+BOOST_AUTO_TEST_CASE(return_does_not_skip_modifier)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public x;
+ modifier setsx {
+ _
+ x = 9;
+ }
+ function f() setsx returns (uint) {
+ return 2;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(2)));
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(9)));
+}
+
+BOOST_AUTO_TEST_CASE(break_in_modifier)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public x;
+ modifier run() {
+ for (uint i = 0; i < 10; i++) {
+ _
+ break;
+ }
+ }
+ function f() run {
+ x++;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(stacked_return_with_modifiers)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public x;
+ modifier run() {
+ for (uint i = 0; i < 10; i++) {
+ _
+ break;
+ }
+ }
+ function f() run {
+ x++;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+}
+
+BOOST_AUTO_TEST_CASE(mutex)
+{
+ char const* sourceCode = R"(
+ contract mutexed {
+ bool locked;
+ modifier protected {
+ if (locked) throw;
+ locked = true;
+ _
+ locked = false;
+ }
+ }
+ contract Fund is mutexed {
+ uint shares;
+ function Fund() { shares = msg.value; }
+ function withdraw(uint amount) protected returns (uint) {
+ // NOTE: It is very bad practice to write this function this way.
+ // Please refer to the documentation of how to do this properly.
+ if (amount > shares) throw;
+ if (!msg.sender.call.value(amount)()) throw;
+ shares -= amount;
+ return shares;
+ }
+ function withdrawUnprotected(uint amount) returns (uint) {
+ // NOTE: It is very bad practice to write this function this way.
+ // Please refer to the documentation of how to do this properly.
+ if (amount > shares) throw;
+ if (!msg.sender.call.value(amount)()) throw;
+ shares -= amount;
+ return shares;
+ }
+ }
+ contract Attacker {
+ Fund public fund;
+ uint callDepth;
+ bool protected;
+ function setProtected(bool _protected) { protected = _protected; }
+ function Attacker(Fund _fund) { fund = _fund; }
+ function attack() returns (uint) {
+ callDepth = 0;
+ return attackInternal();
+ }
+ function attackInternal() internal returns (uint) {
+ if (protected)
+ return fund.withdraw(10);
+ else
+ return fund.withdrawUnprotected(10);
+ }
+ function() {
+ callDepth++;
+ if (callDepth < 4)
+ attackInternal();
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 500, "Fund");
+ auto fund = m_contractAddress;
+ BOOST_CHECK_EQUAL(balanceAt(fund), 500);
+ compileAndRun(sourceCode, 0, "Attacker", encodeArgs(u160(fund)));
+ BOOST_CHECK(callContractFunction("setProtected(bool)", true) == encodeArgs());
+ BOOST_CHECK(callContractFunction("attack()") == encodeArgs());
+ BOOST_CHECK_EQUAL(balanceAt(fund), 500);
+ BOOST_CHECK(callContractFunction("setProtected(bool)", false) == encodeArgs());
+ BOOST_CHECK(callContractFunction("attack()") == encodeArgs(u256(460)));
+ BOOST_CHECK_EQUAL(balanceAt(fund), 460);
+}
+
+BOOST_AUTO_TEST_CASE(failing_ecrecover_invalid_input)
+{
+ // ecrecover should return zero for malformed input
+ // (v should be 27 or 28, not 1)
+ // Note that the precompile does not return zero but returns nothing.
+ char const* sourceCode = R"(
+ contract C {
+ function f() returns (address) {
+ return ecrecover(bytes32(uint(-1)), 1, 2, 3);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0)));
+}
+
+BOOST_AUTO_TEST_CASE(calling_nonexisting_contract_throws)
+{
+ char const* sourceCode = R"(
+ contract D { function g(); }
+ contract C {
+ D d = D(0x1212);
+ function f() returns (uint) {
+ d.g();
+ return 7;
+ }
+ function g() returns (uint) {
+ d.g.gas(200)();
+ return 7;
+ }
+ function h() returns (uint) {
+ d.call(); // this does not throw (low-level)
+ return 7;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("g()") == encodeArgs());
+ BOOST_CHECK(callContractFunction("h()") == encodeArgs(u256(7)));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}