diff options
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | Changelog.md | 2 | ||||
-rw-r--r-- | docs/abi-spec.rst | 4 | ||||
-rw-r--r-- | docs/assembly.rst | 25 | ||||
-rw-r--r-- | docs/metadata.rst | 2 | ||||
-rw-r--r-- | docs/security-considerations.rst | 23 | ||||
-rw-r--r-- | docs/style-guide.rst | 6 | ||||
-rw-r--r-- | docs/using-the-compiler.rst | 21 | ||||
-rw-r--r-- | libjulia/optimiser/README.md | 61 | ||||
-rw-r--r-- | libsolc/CMakeLists.txt | 9 | ||||
-rw-r--r-- | libsolc/libsolc.cpp (renamed from solc/jsonCompiler.cpp) | 2 | ||||
-rw-r--r-- | libsolc/libsolc.h (renamed from solc/jsonCompiler.h) | 0 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 11 | ||||
-rwxr-xr-x | scripts/bytecodecompare/storebytecode.sh | 2 | ||||
-rwxr-xr-x | scripts/test_emscripten.sh | 2 | ||||
-rwxr-xr-x | scripts/travis-emscripten/build_emscripten.sh | 4 | ||||
-rw-r--r-- | solc/CMakeLists.txt | 8 | ||||
-rw-r--r-- | test/CMakeLists.txt | 4 | ||||
-rw-r--r-- | test/fuzzer.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/JSONCompiler.cpp | 2 | ||||
-rw-r--r-- | test/libsolidity/SMTChecker.cpp | 1 | ||||
-rw-r--r-- | test/libsolidity/SolidityABIJSON.cpp | 3 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 4 |
23 files changed, 154 insertions, 47 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 105de851..8993f372 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,9 +43,10 @@ configure_project(TESTS) add_subdirectory(libdevcore) add_subdirectory(libevmasm) add_subdirectory(libsolidity) -add_subdirectory(solc) +add_subdirectory(libsolc) if (NOT EMSCRIPTEN) + add_subdirectory(solc) add_subdirectory(liblll) add_subdirectory(lllc) endif() diff --git a/Changelog.md b/Changelog.md index 248165bb..cf6498a1 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,8 @@ Features: * Inline Assembly: Issue warning for using jump labels (already existed for jump instructions). Bugfixes: + * Type Checker: Suggest the experimental ABI encoder if using ``struct``s as function parameters + (instead of an internal compiler error). ### 0.4.19 (2017-11-30) diff --git a/docs/abi-spec.rst b/docs/abi-spec.rst index c93ce25b..e968fb06 100644 --- a/docs/abi-spec.rst +++ b/docs/abi-spec.rst @@ -377,10 +377,14 @@ As an example, the code :: + pragma solidity ^0.4.19; + pragma experimental ABIEncoderV2; + contract Test { struct S { uint a; uint[] b; T[] c; } struct T { uint x; uint y; } function f(S s, T t, uint a) { } + function g() returns (S s, T t, uint a) {} } would result in the JSON: diff --git a/docs/assembly.rst b/docs/assembly.rst index c233985b..a4fa88c6 100644 --- a/docs/assembly.rst +++ b/docs/assembly.rst @@ -447,31 +447,6 @@ will have a wrong impression about the stack height at label ``two``: three: } -This problem can be fixed by manually adjusting the stack height for the -assembler - you can provide a stack height delta that is added -to the stack height just prior to the label. -Note that you will not have to care about these things if you just use -loops and assembly-level functions. - -As an example how this can be done in extreme cases, please see the following. - -.. code:: - - { - let x := 8 - jump(two) - 0 // This code is unreachable but will adjust the stack height correctly - one: - x := 9 // Now x can be accessed properly. - jump(three) - pop // Similar negative correction. - two: - 7 // push something onto the stack - jump(one) - three: - pop // We have to pop the manually pushed value here again. - } - Declaring Assembly-Local Variables ---------------------------------- diff --git a/docs/metadata.rst b/docs/metadata.rst index dbde87e8..5e37219e 100644 --- a/docs/metadata.rst +++ b/docs/metadata.rst @@ -131,6 +131,8 @@ user interface for the contract. Furthermore, Mist can use the userdoc to display a confirmation message to the user whenever they interact with the contract. +Additional information about Ethereum Natural Specification (NatSpec) can be found `here <https://github.com/ethereum/wiki/wiki/Ethereum-Natural-Specification-Format>`_. + Usage for Source Code Verification ================================== diff --git a/docs/security-considerations.rst b/docs/security-considerations.rst index 337a3d3f..1e2138fa 100644 --- a/docs/security-considerations.rst +++ b/docs/security-considerations.rst @@ -69,10 +69,27 @@ complete contract): } The problem is not too serious here because of the limited gas as part -of ``send``, but it still exposes a weakness: Ether transfer always -includes code execution, so the recipient could be a contract that calls +of ``send``, but it still exposes a weakness: Ether transfer can always +include code execution, so the recipient could be a contract that calls back into ``withdraw``. This would let it get multiple refunds and -basically retrieve all the Ether in the contract. +basically retrieve all the Ether in the contract. In particular, the +following contract will allow an attacker to refund multiple times +as it uses ``call`` which forwards all remaining gas by default: + +:: + + pragma solidity ^0.4.0; + + // THIS CONTRACT CONTAINS A BUG - DO NOT USE + contract Fund { + /// Mapping of ether shares of the contract. + mapping(address => uint) shares; + /// Withdraw your share. + function withdraw() { + if (msg.sender.call.value(shares[msg.sender])()) + shares[msg.sender] = 0; + } + } To avoid re-entrancy, you can use the Checks-Effects-Interactions pattern as outlined further below: diff --git a/docs/style-guide.rst b/docs/style-guide.rst index a438b3d0..5b6f42a2 100644 --- a/docs/style-guide.rst +++ b/docs/style-guide.rst @@ -739,6 +739,12 @@ Modifier Names Use mixedCase. Examples: ``onlyBy``, ``onlyAfter``, ``onlyDuringThePreSale``. +Enums +===== + +Enums, in the style of simple type declarations, should be named using the CapWords style. Examples: ``TokenGroup``, ``Frame``, ``HashStyle``, ``CharacterLocation``. + + Avoiding Naming Collisions ========================== diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index c12750c8..f1f13b82 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -177,7 +177,8 @@ Output Description start: 0, end: 100 ], - // Mandatory: Error type, such as "TypeError", "InternalCompilerError", "Exception", etc + // Mandatory: Error type, such as "TypeError", "InternalCompilerError", "Exception", etc. + // See below for complete list of types. type: "TypeError", // Mandatory: Component where the error originated, such as "general", "ewasm", etc. component: "general", @@ -273,3 +274,21 @@ Output Description } } } + + +Error types +~~~~~~~~~~~ + +1. ``JSONError``: JSON input doesn't conform to the required format, e.g. input is not a JSON object, the language is not supported, etc. +2. ``IOError``: IO and import processing errors, such as unresolvable URL or hash mismatch in supplied sources. +3. ``ParserError``: Source code doesn't conform to the language rules. +4. ``DocstringParsingError``: The NatSpec tags in the comment block cannot be parsed. +5. ``SyntaxError``: Syntactical error, such as ``continue`` is used outside of a ``for`` loop. +6. ``DeclarationError``: Invalid, unresolvable or clashing identifier names. e.g. ``Identifier not found`` +7. ``TypeError``: Error within the type system, such as invalid type conversions, invalid assignments, etc. +8. ``UnimplementedFeatureError``: Feature is not supported by the compiler, but is expected to be supported in future versions. +9. ``InternalCompilerError``: Internal bug triggered in the compiler - this should be reported as an issue. +10. ``Exception``: Unknown failure during compilation - this should be reported as an issue. +11. ``CompilerError``: Invalid use of the compiler stack - this should be reported as an issue. +12. ``FatalError``: Fatal error not processed correctly - this should be reported as an issue. +13. ``Warning``: A warning, which didn't stop the compilation, but should be addressed if possible. diff --git a/libjulia/optimiser/README.md b/libjulia/optimiser/README.md new file mode 100644 index 00000000..771cb707 --- /dev/null +++ b/libjulia/optimiser/README.md @@ -0,0 +1,61 @@ +## IULIA Optimiser + +The iulia optimiser consists of several stages and components that all transform +the AST in a semantically equivalent way. The goal is to end up either with code +that is shorter or at least only marginally longer but will allow further +optimisation steps. + +The optimiser currently follows a purely greedy strategy and does not do any +backtracking. + +## Disambiguator + +The disambiguator takes an AST and returns a fresh copy where all identifiers have +names unique to the input AST. This is a prerequisite for all other optimiser stages. +One of the benefits is that identifier lookup does not need to take scopes into account +and we can basically ignore the result of the analysis phase. + +All subsequent stages have the property that all names stay unique. This means if +a new identifier needs to be introduced, a new unique name is generated. + +## Function Hoister + +The function hoister moves all function definitions to the topmost block. This is +a semantically equivalent transformation as long as it is performed after the +disambiguation stage. The reason is that moving a definition upwards cannot decrease +its visibility and it is impossible to reference variables defined in a different function. + +The benefit of this stage is that function definitions can be lookup up more easily. + +## Function Grouper + +The function grouper has to be applied after the disambiguator and the function hoister. +Its effect is that all topmost elements that are not function definitions are moved +into a single block which is the first satement of the root block. + +After this step, a program has the following normal form: + + { I F... } + +Where I is a block that does not contain any function definitions (not even recursively) +and F is a list of function definitions such that no function contains a function definition. + +## Functional Inliner + +The functional inliner depends on the disambiguator, the function hoister and function grouper. +It performs function inlining such that the result of the inlining is an expression. This can +only be done if the body of the function to be inlined has the form ``{ r := E }`` where ``r`` +is the single return value of the function, ``E`` is an expression and all arguments in the +function call are so-called movable expressions. A movable expression is either a literal, a +variable or a function call (or EVM opcode) which does not have side-effects and also does not +depend on any side-effects. + +As an example, neither ``mload`` nor ``mstore`` would be allowed. + +## Full Function Inliner + +## Variable Eliminator + +## Unused Declaration Pruner + +## Function Unifier diff --git a/libsolc/CMakeLists.txt b/libsolc/CMakeLists.txt new file mode 100644 index 00000000..e67583dd --- /dev/null +++ b/libsolc/CMakeLists.txt @@ -0,0 +1,9 @@ +if (EMSCRIPTEN) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORTED_FUNCTIONS='[\"_compileJSON\",\"_license\",\"_version\",\"_compileJSONMulti\",\"_compileJSONCallback\",\"_compileStandard\"]' -s RESERVED_FUNCTION_POINTERS=20") + add_executable(soljson libsolc.cpp) + target_link_libraries(soljson PRIVATE solidity) +else() + add_library(libsolc libsolc.cpp) + set_target_properties(libsolc PROPERTIES OUTPUT_NAME solc) + target_link_libraries(libsolc PRIVATE solidity) +endif() diff --git a/solc/jsonCompiler.cpp b/libsolc/libsolc.cpp index 23feaa2a..3a6e1521 100644 --- a/solc/jsonCompiler.cpp +++ b/libsolc/libsolc.cpp @@ -20,7 +20,7 @@ * JSON interface for the solidity compiler to be used from Javascript. */ -#include <solc/jsonCompiler.h> +#include <libsolc/libsolc.h> #include <libdevcore/Common.h> #include <libdevcore/JSON.h> #include <libsolidity/interface/StandardCompiler.h> diff --git a/solc/jsonCompiler.h b/libsolc/libsolc.h index c392ce93..c392ce93 100644 --- a/solc/jsonCompiler.h +++ b/libsolc/libsolc.h diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 96160a75..a578ad0f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -570,6 +570,17 @@ bool TypeChecker::visit(FunctionDefinition const& _function) m_errorReporter.typeError(var->location(), "Type is required to live outside storage."); if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction))) m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions."); + if ( + _function.visibility() > FunctionDefinition::Visibility::Internal && + type(*var)->category() == Type::Category::Struct && + !type(*var)->dataStoredIn(DataLocation::Storage) && + !_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) + ) + m_errorReporter.typeError( + var->location(), + "Structs are only supported in the new experimental ABI encoder. " + "Use \"pragma experimental ABIEncoderV2;\" to enable the feature." + ); var->accept(*this); } diff --git a/scripts/bytecodecompare/storebytecode.sh b/scripts/bytecodecompare/storebytecode.sh index 8d4100bf..557e3275 100755 --- a/scripts/bytecodecompare/storebytecode.sh +++ b/scripts/bytecodecompare/storebytecode.sh @@ -40,7 +40,7 @@ TMPDIR=$(mktemp -d) if [[ "$SOLC_EMSCRIPTEN" = "On" ]] then - cp "$REPO_ROOT/build/solc/soljson.js" . + cp "$REPO_ROOT/build/libsolc/soljson.js" . npm install solc cat > solc <<EOF #!/usr/bin/env node diff --git a/scripts/test_emscripten.sh b/scripts/test_emscripten.sh index 4996e957..b659e5e5 100755 --- a/scripts/test_emscripten.sh +++ b/scripts/test_emscripten.sh @@ -29,7 +29,7 @@ set -e REPO_ROOT=$(cd $(dirname "$0")/.. && pwd) -SOLJSON="$REPO_ROOT/build/solc/soljson.js" +SOLJSON="$REPO_ROOT/build/libsolc/soljson.js" DIR=$(mktemp -d) ( diff --git a/scripts/travis-emscripten/build_emscripten.sh b/scripts/travis-emscripten/build_emscripten.sh index bf460e8e..56826997 100755 --- a/scripts/travis-emscripten/build_emscripten.sh +++ b/scripts/travis-emscripten/build_emscripten.sh @@ -87,8 +87,8 @@ make -j 4 cd .. mkdir -p upload -cp build/solc/soljson.js upload/ -cp build/solc/soljson.js ./ +cp build/libsolc/soljson.js upload/ +cp build/libsolc/soljson.js ./ OUTPUT_SIZE=`ls -la soljson.js` diff --git a/solc/CMakeLists.txt b/solc/CMakeLists.txt index 656b27c3..d9b12a06 100644 --- a/solc/CMakeLists.txt +++ b/solc/CMakeLists.txt @@ -10,14 +10,6 @@ target_link_libraries(solc PRIVATE solidity ${Boost_PROGRAM_OPTIONS_LIBRARIES}) include(GNUInstallDirs) install(TARGETS solc DESTINATION "${CMAKE_INSTALL_BINDIR}") -if (EMSCRIPTEN) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s EXPORTED_FUNCTIONS='[\"_compileJSON\",\"_license\",\"_version\",\"_compileJSONMulti\",\"_compileJSONCallback\",\"_compileStandard\"]' -s RESERVED_FUNCTION_POINTERS=20") - add_executable(soljson jsonCompiler.cpp) -else() - add_library(soljson jsonCompiler.cpp) -endif() -target_link_libraries(soljson PRIVATE solidity) - if(SOLC_LINK_STATIC AND UNIX AND NOT APPLE) # Produce solc as statically linked binary (includes C/C++ standard libraries) # This is not supported on macOS, see diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6a8a4399..f36ad4c5 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -3,7 +3,7 @@ list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/fuzzer.cpp") file(GLOB_RECURSE headers "*.h") add_executable(soltest ${sources} ${headers}) -target_link_libraries(soltest PRIVATE soljson solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) +target_link_libraries(soltest PRIVATE libsolc solidity lll evmasm devcore ${Boost_UNIT_TEST_FRAMEWORK_LIBRARIES}) add_executable(solfuzzer fuzzer.cpp) -target_link_libraries(solfuzzer soljson evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES}) +target_link_libraries(solfuzzer PRIVATE libsolc evmasm ${Boost_PROGRAM_OPTIONS_LIBRARIES}) diff --git a/test/fuzzer.cpp b/test/fuzzer.cpp index 53ba7201..578e63a4 100644 --- a/test/fuzzer.cpp +++ b/test/fuzzer.cpp @@ -20,7 +20,7 @@ #include <libevmasm/Assembly.h> #include <libevmasm/ConstantOptimiser.h> -#include <solc/jsonCompiler.h> +#include <libsolc/libsolc.h> #include <json/json.h> diff --git a/test/libsolidity/JSONCompiler.cpp b/test/libsolidity/JSONCompiler.cpp index 7dc4808b..0c904c77 100644 --- a/test/libsolidity/JSONCompiler.cpp +++ b/test/libsolidity/JSONCompiler.cpp @@ -23,7 +23,7 @@ #include <boost/test/unit_test.hpp> #include <libdevcore/JSON.h> #include <libsolidity/interface/Version.h> -#include <solc/jsonCompiler.h> +#include <libsolc/libsolc.h> #include "../Metadata.h" #include "../TestHelper.h" diff --git a/test/libsolidity/SMTChecker.cpp b/test/libsolidity/SMTChecker.cpp index 38d02601..3a65aa43 100644 --- a/test/libsolidity/SMTChecker.cpp +++ b/test/libsolidity/SMTChecker.cpp @@ -94,6 +94,7 @@ BOOST_AUTO_TEST_CASE(warn_on_typecast) BOOST_AUTO_TEST_CASE(warn_on_struct) { string text = R"( + pragma experimental ABIEncoderV2; contract C { struct A { uint a; uint b; } function f() public pure returns (A) { diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp index 33962730..26bfb6d0 100644 --- a/test/libsolidity/SolidityABIJSON.cpp +++ b/test/libsolidity/SolidityABIJSON.cpp @@ -942,6 +942,7 @@ BOOST_AUTO_TEST_CASE(function_type) BOOST_AUTO_TEST_CASE(return_structs) { char const* text = R"( + pragma experimental ABIEncoderV2; contract C { struct S { uint a; T[] sub; } struct T { uint[2] x; } @@ -991,6 +992,7 @@ BOOST_AUTO_TEST_CASE(return_structs) BOOST_AUTO_TEST_CASE(return_structs_with_contracts) { char const* text = R"( + pragma experimental ABIEncoderV2; contract C { struct S { C[] x; C y; } function f() returns (S s, C c) { @@ -1090,6 +1092,7 @@ BOOST_AUTO_TEST_CASE(event_structs) BOOST_AUTO_TEST_CASE(structs_in_libraries) { char const* text = R"( + pragma experimental ABIEncoderV2; library L { struct S { uint a; T[] sub; bytes b; } struct T { uint[2] x; } diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index 97d359e8..39dba0de 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -602,6 +602,7 @@ BOOST_AUTO_TEST_CASE(enum_external_type) BOOST_AUTO_TEST_CASE(external_structs) { char const* text = R"( + pragma experimental ABIEncoderV2; contract Test { enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } struct Empty {} @@ -629,6 +630,7 @@ BOOST_AUTO_TEST_CASE(external_structs) BOOST_AUTO_TEST_CASE(external_structs_in_libraries) { char const* text = R"( + pragma experimental ABIEncoderV2; library Test { enum ActionChoices { GoLeft, GoRight, GoStraight, Sit } struct Empty {} @@ -3511,6 +3513,7 @@ BOOST_AUTO_TEST_CASE(using_for_not_used) BOOST_AUTO_TEST_CASE(library_memory_struct) { char const* text = R"( + pragma experimental ABIEncoderV2; library c { struct S { uint x; } function f() public returns (S ) {} @@ -5696,6 +5699,7 @@ BOOST_AUTO_TEST_CASE(constructible_internal_constructor) BOOST_AUTO_TEST_CASE(return_structs) { char const* text = R"( + pragma experimental ABIEncoderV2; contract C { struct S { uint a; T[] sub; } struct T { uint[] x; } |