aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--libsolidity/codegen/CompilerContext.cpp2
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp1
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp1
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp154
4 files changed, 157 insertions, 1 deletions
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 9c5dc89c..51f76399 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -127,6 +127,8 @@ void CompilerContext::addVariable(VariableDeclaration const& _declaration,
unsigned _offsetToCurrent)
{
solAssert(m_asm->deposit() >= 0 && unsigned(m_asm->deposit()) >= _offsetToCurrent, "");
+ unsigned sizeOnStack = _declaration.annotation().type->sizeOnStack();
+ solAssert(sizeOnStack == 1 || sizeOnStack == 2, "");
m_localVariables[&_declaration].push_back(unsigned(m_asm->deposit()) - _offsetToCurrent);
}
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 92c45227..5adce4a0 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -1172,6 +1172,7 @@ void CompilerUtils::popStackSlots(size_t _amount)
void CompilerUtils::popAndJump(unsigned _toHeight, eth::AssemblyItem const& _jumpTo)
{
+ solAssert(m_context.stackHeight() >= _toHeight, "");
unsigned amount = m_context.stackHeight() - _toHeight;
popStackSlots(amount);
m_context.appendJumpTo(_jumpTo);
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 474d2b68..207e0af7 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -999,6 +999,7 @@ eth::AssemblyPointer ContractCompiler::cloneRuntime() const
void ContractCompiler::popScopedVariables(ASTNode const* _node)
{
unsigned blockHeight = m_scopeStackHeight.at(m_modifierDepth).at(_node);
+ solAssert(m_context.stackHeight() >= blockHeight, "");
unsigned stackDiff = m_context.stackHeight() - blockHeight;
CompilerUtils(m_context).popStackSlots(stackDiff);
m_context.removeVariablesAboveStackHeight(blockHeight);
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 52fdfed7..ae92810d 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -523,6 +523,45 @@ BOOST_AUTO_TEST_CASE(do_while_loop_continue)
ABI_CHECK(callContractFunction("f()"), encodeArgs(42));
}
+BOOST_AUTO_TEST_CASE(array_multiple_local_vars)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(uint256[] seq) public pure returns (uint256) {
+ uint i = 0;
+ uint sum = 0;
+ while (i < seq.length)
+ {
+ uint idx = i;
+ if (idx >= 10) break;
+ uint x = seq[idx];
+ if (x >= 1000) {
+ uint n = i + 1;
+ i = n;
+ continue;
+ }
+ else {
+ uint y = sum + x;
+ sum = y;
+ }
+ if (sum >= 500) return sum;
+ i++;
+ }
+ return sum;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+
+ ABI_CHECK(callContractFunction("f(uint256[])", 32, 3, u256(1000), u256(1), u256(2)), encodeArgs(3));
+ ABI_CHECK(callContractFunction("f(uint256[])", 32, 3, u256(100), u256(500), u256(300)), encodeArgs(600));
+ ABI_CHECK(callContractFunction(
+ "f(uint256[])", 32, 11,
+ u256(1), u256(2), u256(3), u256(4), u256(5), u256(6), u256(7), u256(8), u256(9), u256(10), u256(111)
+ ), encodeArgs(55));
+}
+
+
BOOST_AUTO_TEST_CASE(do_while_loop_multiple_local_vars)
{
char const* sourceCode = R"(
@@ -628,21 +667,30 @@ BOOST_AUTO_TEST_CASE(nested_loops)
BOOST_AUTO_TEST_CASE(nested_loops_multiple_local_vars)
{
// tests that break and continue statements in nested loops jump to the correct place
+ // and free local variables properly
char const* sourceCode = R"(
contract test {
function f(uint x) returns(uint y) {
while (x > 0) {
uint z = x + 10;
uint k = z + 1;
- if (k > 20) break;
+ if (k > 20) {
+ break;
+ uint p = 100;
+ k += p;
+ }
if (k > 15) {
x--;
continue;
+ uint t = 1000;
+ x += t;
}
while (k > 10) {
uint m = k - 1;
if (m == 10) return x;
return k;
+ uint h = 10000;
+ z += h;
}
x--;
break;
@@ -727,6 +775,66 @@ BOOST_AUTO_TEST_CASE(for_loop_multiple_local_vars)
testContractAgainstCppOnRange("f(uint256)", for_loop, 0, 12);
}
+BOOST_AUTO_TEST_CASE(nested_for_loop_multiple_local_vars)
+{
+ char const* sourceCode = R"(
+ contract test {
+ function f(uint x) public pure returns(uint r) {
+ for (uint i = 0; i < 5; i++)
+ {
+ uint z = x + 1;
+ if (z < 3) {
+ break;
+ uint p = z + 2;
+ }
+ for (uint j = 0; j < 5; j++)
+ {
+ uint k = z * 2;
+ if (j + k < 8) {
+ x++;
+ continue;
+ uint t = z * 3;
+ }
+ x++;
+ if (x > 20) {
+ return 84;
+ uint h = x + 42;
+ }
+ }
+ if (x > 30) {
+ return 42;
+ uint b = 0xcafe;
+ }
+ }
+ return 42;
+ }
+ }
+ )";
+ compileAndRun(sourceCode);
+
+ auto for_loop = [](u256 n) -> u256
+ {
+ for (u256 i = 0; i < 5; i++)
+ {
+ u256 z = n + 1;
+ if (z < 3) break;
+ for (u256 j = 0; j < 5; j++)
+ {
+ u256 k = z * 2;
+ if (j + k < 8) {
+ n++;
+ continue;
+ }
+ n++;
+ if (n > 20) return 84;
+ }
+ if (n > 30) return 42;
+ }
+ return 42;
+ };
+
+ testContractAgainstCppOnRange("f(uint256)", for_loop, 0, 12);
+}
BOOST_AUTO_TEST_CASE(for_loop)
{
@@ -9396,6 +9504,50 @@ BOOST_AUTO_TEST_CASE(break_in_modifier)
ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(1)));
}
+BOOST_AUTO_TEST_CASE(continue_in_modifier)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public x;
+ modifier run() {
+ for (uint i = 0; i < 10; i++) {
+ if (i % 2 == 1) continue;
+ _;
+ }
+ }
+ function f() run {
+ x++;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0)));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs());
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(5)));
+}
+
+BOOST_AUTO_TEST_CASE(return_in_modifier)
+{
+ char const* sourceCode = R"(
+ contract C {
+ uint public x;
+ modifier run() {
+ for (uint i = 1; i < 10; i++) {
+ if (i == 5) return;
+ _;
+ }
+ }
+ function f() run {
+ x++;
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(0)));
+ ABI_CHECK(callContractFunction("f()"), encodeArgs());
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(u256(4)));
+}
+
BOOST_AUTO_TEST_CASE(stacked_return_with_modifiers)
{
char const* sourceCode = R"(