diff options
author | chriseth <chris@ethereum.org> | 2017-04-26 23:47:48 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-04-26 23:47:48 +0800 |
commit | 2c1fb46bc341d9e44074af23cd4eadd3a9f732c5 (patch) | |
tree | 58fba734d5ecf3330e8a62154ffa994bab8c551b /test/libsolidity | |
parent | c02bcaea043032107dd6343e5c68cc948a6a88c2 (diff) | |
parent | 2002447b10c23b5769f11f74c51e9a19c59241a3 (diff) | |
download | dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.tar dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.tar.gz dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.tar.bz2 dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.tar.lz dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.tar.xz dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.tar.zst dexon-solidity-2c1fb46bc341d9e44074af23cd4eadd3a9f732c5.zip |
Merge pull request #1711 from ethereum/asmfunctions
Assembly: Analysis stage for functions.
Diffstat (limited to 'test/libsolidity')
-rw-r--r-- | test/libsolidity/InlineAssembly.cpp | 99 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 45 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 42 |
3 files changed, 148 insertions, 38 deletions
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 9035599b..0e9b640a 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -30,6 +30,7 @@ #include <libevmasm/Assembly.h> #include <boost/optional.hpp> +#include <boost/algorithm/string/replace.hpp> #include <string> #include <memory> @@ -63,7 +64,7 @@ boost::optional<Error> parseAndReturnFirstError(string const& _source, bool _ass } if (!success) { - BOOST_CHECK_EQUAL(stack.errors().size(), 1); + BOOST_REQUIRE_EQUAL(stack.errors().size(), 1); return *stack.errors().front(); } else @@ -137,22 +138,22 @@ BOOST_AUTO_TEST_CASE(smoke_test) BOOST_AUTO_TEST_CASE(simple_instructions) { - BOOST_CHECK(successParse("{ dup1 dup1 mul dup1 sub }")); + BOOST_CHECK(successParse("{ dup1 dup1 mul dup1 sub pop }")); } BOOST_AUTO_TEST_CASE(suicide_selfdestruct) { - BOOST_CHECK(successParse("{ suicide selfdestruct }")); + BOOST_CHECK(successParse("{ 0x01 suicide 0x02 selfdestruct }")); } BOOST_AUTO_TEST_CASE(keywords) { - BOOST_CHECK(successParse("{ byte return address }")); + BOOST_CHECK(successParse("{ 1 2 byte 2 return address pop }")); } BOOST_AUTO_TEST_CASE(constants) { - BOOST_CHECK(successParse("{ 7 8 mul }")); + BOOST_CHECK(successParse("{ 7 8 mul pop }")); } BOOST_AUTO_TEST_CASE(vardecl) @@ -162,37 +163,43 @@ BOOST_AUTO_TEST_CASE(vardecl) BOOST_AUTO_TEST_CASE(assignment) { - BOOST_CHECK(successParse("{ 7 8 add =: x }")); + BOOST_CHECK(successParse("{ let x := 2 7 8 add =: x }")); } BOOST_AUTO_TEST_CASE(label) { - BOOST_CHECK(successParse("{ 7 abc: 8 eq abc jump }")); + BOOST_CHECK(successParse("{ 7 abc: 8 eq abc jump pop }")); } BOOST_AUTO_TEST_CASE(label_complex) { - BOOST_CHECK(successParse("{ 7 abc: 8 eq jump(abc) jumpi(eq(7, 8), abc) }")); + BOOST_CHECK(successParse("{ 7 abc: 8 eq jump(abc) jumpi(eq(7, 8), abc) pop }")); } BOOST_AUTO_TEST_CASE(functional) { - BOOST_CHECK(successParse("{ add(7, mul(6, x)) add mul(7, 8) }")); + BOOST_CHECK(successParse("{ let x := 2 add(7, mul(6, x)) mul(7, 8) add =: x }")); } BOOST_AUTO_TEST_CASE(functional_assignment) { - BOOST_CHECK(successParse("{ x := 7 }")); + BOOST_CHECK(successParse("{ let x := 2 x := 7 }")); } BOOST_AUTO_TEST_CASE(functional_assignment_complex) { - BOOST_CHECK(successParse("{ x := add(7, mul(6, x)) add mul(7, 8) }")); + BOOST_CHECK(successParse("{ let x := 2 x := add(7, mul(6, x)) mul(7, 8) add }")); } BOOST_AUTO_TEST_CASE(vardecl_complex) { - BOOST_CHECK(successParse("{ let x := add(7, mul(6, x)) add mul(7, 8) }")); + BOOST_CHECK(successParse("{ let y := 2 let x := add(7, mul(6, y)) add mul(7, 8) }")); +} + +BOOST_AUTO_TEST_CASE(variable_use_before_decl) +{ + CHECK_PARSE_ERROR("{ x := 2 let x := 3 }", DeclarationError, "Variable x used before it was declared."); + CHECK_PARSE_ERROR("{ let x := mul(2, x) }", DeclarationError, "Variable x used before it was declared."); } BOOST_AUTO_TEST_CASE(blocks) @@ -212,7 +219,28 @@ BOOST_AUTO_TEST_CASE(function_definitions_multiple_args) BOOST_AUTO_TEST_CASE(function_calls) { - BOOST_CHECK(successParse("{ g(1, 2, f(mul(2, 3))) x() }")); + BOOST_CHECK(successParse("{ function f(a) -> (b) {} function g(a, b, c) {} function x() { g(1, 2, f(mul(2, 3))) x() } }")); +} + +BOOST_AUTO_TEST_CASE(opcode_for_functions) +{ + CHECK_PARSE_ERROR("{ function gas() { } }", ParserError, "Cannot use instruction names for identifier names."); +} + +BOOST_AUTO_TEST_CASE(opcode_for_function_args) +{ + CHECK_PARSE_ERROR("{ function f(gas) { } }", ParserError, "Cannot use instruction names for identifier names."); + CHECK_PARSE_ERROR("{ function f() -> (gas) { } }", ParserError, "Cannot use instruction names for identifier names."); +} + +BOOST_AUTO_TEST_CASE(name_clashes) +{ + CHECK_PARSE_ERROR("{ let g := 2 function g() { } }", DeclarationError, "Function name g already taken in this scope"); +} + +BOOST_AUTO_TEST_CASE(variable_access_cross_functions) +{ + CHECK_PARSE_ERROR("{ let x := 2 function g() { x pop } }", DeclarationError, "Identifier not found."); } BOOST_AUTO_TEST_SUITE_END() @@ -226,7 +254,7 @@ BOOST_AUTO_TEST_CASE(print_smoke) BOOST_AUTO_TEST_CASE(print_instructions) { - parsePrintCompare("{\n 7\n 8\n mul\n dup10\n add\n}"); + parsePrintCompare("{\n 7\n 8\n mul\n dup10\n add\n pop\n}"); } BOOST_AUTO_TEST_CASE(print_subblock) @@ -236,7 +264,7 @@ BOOST_AUTO_TEST_CASE(print_subblock) BOOST_AUTO_TEST_CASE(print_functional) { - parsePrintCompare("{\n mul(sload(0x12), 7)\n}"); + parsePrintCompare("{\n let x := mul(sload(0x12), 7)\n}"); } BOOST_AUTO_TEST_CASE(print_label) @@ -251,13 +279,13 @@ BOOST_AUTO_TEST_CASE(print_assignments) BOOST_AUTO_TEST_CASE(print_string_literals) { - parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n}"); + parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n pop\n}"); } BOOST_AUTO_TEST_CASE(print_string_literal_unicode) { - string source = "{ \"\\u1bac\" }"; - string parsed = "{\n \"\\xe1\\xae\\xac\"\n}"; + string source = "{ let x := \"\\u1bac\" }"; + string parsed = "{\n let x := \"\\xe1\\xae\\xac\"\n}"; assembly::InlineAssemblyStack stack; BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(source)))); BOOST_REQUIRE(stack.errors().empty()); @@ -272,7 +300,21 @@ BOOST_AUTO_TEST_CASE(function_definitions_multiple_args) BOOST_AUTO_TEST_CASE(function_calls) { - parsePrintCompare("{\n g(1, mul(2, x), f(mul(2, 3)))\n x()\n}"); + string source = R"({ + function y() + { + } + function f(a) -> (b) + { + } + function g(a, b, c) + { + } + g(1, mul(2, address), f(mul(2, caller))) + y() +})"; + boost::replace_all(source, "\t", " "); + parsePrintCompare(source); } BOOST_AUTO_TEST_SUITE_END() @@ -291,27 +333,32 @@ BOOST_AUTO_TEST_CASE(oversize_string_literals) BOOST_AUTO_TEST_CASE(assignment_after_tag) { - BOOST_CHECK(successParse("{ let x := 1 { tag: =: x } }")); + BOOST_CHECK(successParse("{ let x := 1 { 7 tag: =: x } }")); } BOOST_AUTO_TEST_CASE(magic_variables) { - CHECK_ASSEMBLE_ERROR("{ this pop }", DeclarationError, "Identifier not found or not unique"); - CHECK_ASSEMBLE_ERROR("{ ecrecover pop }", DeclarationError, "Identifier not found or not unique"); - BOOST_CHECK(successAssemble("{ let ecrecover := 1 ecrecover }")); + CHECK_ASSEMBLE_ERROR("{ this pop }", DeclarationError, "Identifier not found"); + CHECK_ASSEMBLE_ERROR("{ ecrecover pop }", DeclarationError, "Identifier not found"); + BOOST_CHECK(successAssemble("{ let ecrecover := 1 ecrecover pop }")); +} + +BOOST_AUTO_TEST_CASE(stack_variables) +{ + BOOST_CHECK(successAssemble("{ let y := 3 { 2 { let x := y } pop} }")); } BOOST_AUTO_TEST_CASE(imbalanced_stack) { BOOST_CHECK(successAssemble("{ 1 2 mul pop }", false)); - CHECK_ASSEMBLE_ERROR("{ 1 }", Warning, "Inline assembly block is not balanced. It leaves"); - CHECK_ASSEMBLE_ERROR("{ pop }", Warning, "Inline assembly block is not balanced. It takes"); + CHECK_ASSEMBLE_ERROR("{ 1 }", DeclarationError, "Unbalanced stack at the end of a block: 1 surplus item(s)."); + CHECK_ASSEMBLE_ERROR("{ pop }", DeclarationError, "Unbalanced stack at the end of a block: 1 missing item(s)."); BOOST_CHECK(successAssemble("{ let x := 4 7 add }", false)); } BOOST_AUTO_TEST_CASE(error_tag) { - BOOST_CHECK(successAssemble("{ invalidJumpLabel }")); + BOOST_CHECK(successAssemble("{ jump(invalidJumpLabel) }")); } BOOST_AUTO_TEST_CASE(designated_invalid_instruction) diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 8dd5042a..f2f4b8b0 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -7426,18 +7426,52 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_access) uint16 x; uint16 public y; uint public z; - function f() { - // we know that z is aligned because it is too large, so we just discard its - // intra-slot offset value - assembly { 7 z pop sstore } + function f() returns (bool) { + uint off1; + uint off2; + assembly { + sstore(z_slot, 7) + off1 := z_offset + off2 := y_offset + } + assert(off1 == 0); + assert(off2 == 2); + return true; } } )"; compileAndRun(sourceCode, 0, "C"); - BOOST_CHECK(callContractFunction("f()") == encodeArgs()); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(true)); BOOST_CHECK(callContractFunction("z()") == encodeArgs(u256(7))); } +BOOST_AUTO_TEST_CASE(inline_assembly_storage_access_via_pointer) +{ + char const* sourceCode = R"( + contract C { + struct Data { uint contents; } + uint public separator; + Data public a; + uint public separator2; + function f() returns (bool) { + Data x = a; + uint off; + assembly { + sstore(x_slot, 7) + off := x_offset + } + assert(off == 0); + return true; + } + } + )"; + compileAndRun(sourceCode, 0, "C"); + BOOST_CHECK(callContractFunction("f()") == encodeArgs(true)); + BOOST_CHECK(callContractFunction("a()") == encodeArgs(u256(7))); + BOOST_CHECK(callContractFunction("separator()") == encodeArgs(u256(0))); + BOOST_CHECK(callContractFunction("separator2()") == encodeArgs(u256(0))); +} + BOOST_AUTO_TEST_CASE(inline_assembly_jumps) { char const* sourceCode = R"( @@ -7474,6 +7508,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_function_access) assembly { _x jump(g) + pop } } } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index b98c3706..f88f600a 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -4997,7 +4997,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_positive_stack) } } )"; - CHECK_WARNING(text, "Inline assembly block is not balanced"); + CHECK_ERROR(text, DeclarationError, "Unbalanced stack at the end of a block: 1 surplus item(s)."); } BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_negative_stack) @@ -5011,7 +5011,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_negative_stack) } } )"; - CHECK_WARNING(text, "Inline assembly block is not balanced"); + CHECK_ERROR(text, DeclarationError, "Unbalanced stack at the end of a block: 1 missing item(s)."); } BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_two_stack_load) @@ -5024,7 +5024,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_unbalanced_two_stack_load) } } )"; - CHECK_WARNING(text, "Inline assembly block is not balanced"); + CHECK_ERROR(text, TypeError, "Only local variables are supported. To access storage variables,"); } BOOST_AUTO_TEST_CASE(inline_assembly_in_modifier) @@ -5053,12 +5053,11 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage) function f() { assembly { x := 2 - pop } } } )"; - CHECK_ERROR(text, DeclarationError, "not found, not unique or not lvalue."); + CHECK_ERROR(text, TypeError, "Only local variables are supported. To access storage variables,"); } BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers) @@ -5069,7 +5068,6 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers) modifier m { assembly { x := 2 - pop } _; } @@ -5077,7 +5075,37 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_in_modifiers) } } )"; - CHECK_ERROR(text, DeclarationError, ""); + CHECK_ERROR(text, TypeError, "Only local variables are supported. To access storage variables,"); +} + +BOOST_AUTO_TEST_CASE(inline_assembly_constant_assign) +{ + char const* text = R"( + contract test { + uint constant x = 1; + function f() { + assembly { + x := 2 + } + } + } + )"; + CHECK_ERROR(text, TypeError, "Constant variables not supported by inline assembly"); +} + +BOOST_AUTO_TEST_CASE(inline_assembly_constant_access) +{ + char const* text = R"( + contract test { + uint constant x = 1; + function f() { + assembly { + let y := x + } + } + } + )"; + CHECK_ERROR(text, TypeError, "Constant variables not supported by inline assembly"); } BOOST_AUTO_TEST_CASE(invalid_mobile_type) |