diff options
-rw-r--r-- | Changelog.md | 4 | ||||
-rw-r--r-- | README.md | 4 | ||||
-rw-r--r-- | docs/050-breaking-changes.rst | 2 | ||||
-rw-r--r-- | docs/using-the-compiler.rst | 38 | ||||
-rw-r--r-- | libevmasm/GasMeter.cpp | 3 | ||||
-rw-r--r-- | libevmasm/Instruction.h | 12 | ||||
-rw-r--r-- | libjulia/backends/evm/EVMCodeTransform.cpp | 8 | ||||
-rw-r--r-- | libsolidity/analysis/ReferencesResolver.cpp | 2 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.cpp | 17 | ||||
-rw-r--r-- | libsolidity/interface/EVMVersion.h | 1 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 12 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol | 15 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol | 15 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/array/length/parentheses.sol | 2 | ||||
-rw-r--r-- | test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol | 2 |
16 files changed, 101 insertions, 40 deletions
diff --git a/Changelog.md b/Changelog.md index 21de2ce6..15edb6d5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -84,11 +84,12 @@ Language Features: * General: Allow ``mapping`` storage pointers as arguments and return values in all internal functions. * General: Allow ``struct``s in interfaces. * General: Provide access to the ABI decoder through ``abi.decode(bytes memory data, (...))``. + * General: Disallow zero length for fixed-size arrays. * Parser: Accept the ``address payable`` type during parsing. Compiler Features: * C API (``libsolc``): Export the ``solidity_license``, ``solidity_version`` and ``solidity_compile`` methods. - * Code Generator: ``CREATE2`` instruction has been updated to match EIP1014 (aka "Skinny CREATE2"). + * Code Generator: ``CREATE2`` instruction has been updated to match EIP1014 (aka "Skinny CREATE2"). It also is accepted as part of Constantinople. * Type Checker: Nicer error message when trying to reference overloaded identifiers in inline assembly. * Type Checker: Show named argument in case of error. * Type System: IntegerType is split into IntegerType and AddressType internally. @@ -101,6 +102,7 @@ Bugfixes: * Tests: Fix chain parameters to make ipc tests work with newer versions of cpp-ethereum. * Code Generator: Fix allocation of byte arrays (zeroed out too much memory). * Code Generator: Properly handle negative number literals in ABIEncoderV2. + * Code Generator: Do not crash on using a length of zero for multidimensional fixed-size arrays. * Commandline Interface: Correctly handle paths with backslashes on windows. * Fix NatSpec json output for `@notice` and `@dev` tags on contract definitions. * Optimizer: Correctly estimate gas costs of constants for special cases. @@ -29,8 +29,10 @@ Instructions about how to build and install the Solidity compiler can be found i A "Hello World" program in Solidity is of even less use than in other languages, but still: ``` +pragma solidity ^0.4.16; + contract HelloWorld { - function f() pure returns (string memory) { + function helloWorld() external pure returns (string memory) { return "Hello, World!"; } } diff --git a/docs/050-breaking-changes.rst b/docs/050-breaking-changes.rst index 51864571..1c12daa8 100644 --- a/docs/050-breaking-changes.rst +++ b/docs/050-breaking-changes.rst @@ -222,6 +222,8 @@ Variables * Detecting cyclic dependencies in variables and structs is limited in recursion to 256. +* Fixed-size arrays with a length of zero are now disallowed. + Syntax ------ diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 1e4bbecc..39520bec 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -10,13 +10,17 @@ Using the Commandline Compiler ****************************** .. note:: - This section doesn't apply to :ref:`solcjs <solcjs>`. + This section does not apply to :ref:`solcjs <solcjs>`, not even if it is used in commandline mode. One of the build targets of the Solidity repository is ``solc``, the solidity commandline compiler. Using ``solc --help`` provides you with an explanation of all options. The compiler can produce various outputs, ranging from simple binaries and assembly over an abstract syntax tree (parse tree) to estimations of gas usage. If you only want to compile a single file, you run it as ``solc --bin sourceFile.sol`` and it will print the binary. If you want to get some of the more advanced output variants of ``solc``, it is probably better to tell it to output everything to separate files using ``solc -o outputDirectory --bin --ast --asm sourceFile.sol``. -Before you deploy your contract, activate the optimizer while compiling using ``solc --optimize --bin sourceFile.sol``. By default, the optimizer will optimize the contract for 200 runs. If you want to optimize for initial contract deployment and get the smallest output, set it to ``--runs=1``. If you expect many transactions and don't care for higher deployment cost and output size, set ``--runs`` to a high number. +Before you deploy your contract, activate the optimizer when compiling using ``solc --optimize --bin sourceFile.sol``. +By default, the optimizer will optimize the contract assuming it is called 200 times across its lifetime. +If you want the initial contract deployment to be cheaper and the later function executions to be more expensive, +set it to ``--runs=1``. If you expect many transactions and do not care for higher deployment cost and +output size, set ``--runs`` to a high number. The commandline compiler will automatically read imported files from the filesystem, but it is also possible to provide path redirects using ``prefix=path`` in the following way: @@ -43,7 +47,7 @@ Either add ``--libraries "Math:0x12345678901234567890 Heap:0xabcdef0123456"`` to If ``solc`` is called with the option ``--link``, all input files are interpreted to be unlinked binaries (hex-encoded) in the ``__LibraryName____``-format given above and are linked in-place (if the input is read from stdin, it is written to stdout). All options except ``--libraries`` are ignored (including ``-o``) in this case. -If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. +If ``solc`` is called with the option ``--standard-json``, it will expect a JSON input (as explained below) on the standard input, and return a JSON output on the standard output. This is the recommended interface for more complex and especially automated uses. .. _evm-version: .. index:: ! EVM version, compile target @@ -60,18 +64,23 @@ version to compile for to avoid particular features or behaviours. behaviour. Please ensure, especially if running a private chain, that you use matching EVM versions. -You use the ``--evm-version`` option on the command line: +On the command line, you can select the EVM version as follows: .. code-block:: shell solc --evm-version <VERSION> contract.sol -Or if using the :ref:`standard JSON interface <compiler-api>`, with the ``evmVersion`` key: +In the :ref:`standard JSON interface <compiler-api>`, use the ``"evmVersion"`` +key in the ``"settings"`` field: -.. code-block:: json +.. code-block:: none { - "evmVersion": "<VERSION>" + "sources": { ... }, + "settings": { + "optimizer": { ... }, + "evmVersion": "<VERSION>" + } } Target options @@ -80,7 +89,7 @@ Target options Below is a list of target EVM versions and the compiler-relevant changes introduced at each version. Backward compatibility is not guaranteed between each version. -- ``homestead`` +- ``homestead`` (oldest version) - ``tangerineWhistle`` - gas cost for access to other accounts increased, relevant for gas estimation and the optimizer. - all gas sent by default for external calls, previously a certain amount had to be retained. @@ -88,7 +97,7 @@ at each version. Backward compatibility is not guaranteed between each version. - gas cost for the ``exp`` opcode increased, relevant for gas estimation and the optimizer. - ``byzantium`` (**default**) - opcodes ``returndatacopy``, ``returndatasize`` and ``staticcall`` are available in assembly. - - the ``staticcall`` opcode is used when calling view or pure functions, which prevents the functions from modifying state at the EVM level, i.e., even applies when you use invalid type conversions. + - the ``staticcall`` opcode is used when calling non-library view or pure functions, which prevents the functions from modifying state at the EVM level, i.e., even applies when you use invalid type conversions. - it is possible to access dynamic data returned from function calls. - ``revert`` opcode introduced, which means that ``revert()`` will not waste gas. - ``constantinople`` (still in progress) @@ -100,11 +109,16 @@ at each version. Backward compatibility is not guaranteed between each version. Compiler Input and Output JSON Description ****************************************** -These JSON formats are used by the compiler API as well as are available through ``solc``. These are subject to change, -some fields are optional (as noted), but it is aimed at to only make backwards compatible changes. +The recommended way to interface with the Solidity compiler especially for +more complex and automated setups is the so-called JSON-input-output interface. +The same interface is provided by all distributions of the compiler. + +The fields are generally subject to change, +some are optional (as noted), but we try to only make backwards compatible changes. The compiler API expects a JSON formatted input and outputs the compilation result in a JSON formatted output. +The following subsections describe the format through an example. Comments are of course not permitted and used here only for explanatory purposes. Input Description @@ -113,7 +127,7 @@ Input Description .. code-block:: none { - // Required: Source code language, such as "Solidity", "serpent", "lll", "assembly", etc. + // Required: Source code language, such as "Solidity", "Vyper", "lll", "assembly", etc. language: "Solidity", // Required sources: diff --git a/libevmasm/GasMeter.cpp b/libevmasm/GasMeter.cpp index 3554f809..b525c301 100644 --- a/libevmasm/GasMeter.cpp +++ b/libevmasm/GasMeter.cpp @@ -125,8 +125,7 @@ GasMeter::GasConsumption GasMeter::estimateMax(AssemblyItem const& _item, bool _ case Instruction::LOG3: case Instruction::LOG4: { - unsigned n = unsigned(_item.instruction()) - unsigned(Instruction::LOG0); - gas = GasCosts::logGas + GasCosts::logTopicGas * n; + gas = GasCosts::logGas + GasCosts::logTopicGas * getLogNumber(_item.instruction()); gas += memoryGas(0, -1); if (u256 const* value = classes.knownConstant(m_state->relativeStackElement(-1))) gas += GasCosts::logDataGas * (*value); diff --git a/libevmasm/Instruction.h b/libevmasm/Instruction.h index e2e2b63e..50c1f47d 100644 --- a/libevmasm/Instruction.h +++ b/libevmasm/Instruction.h @@ -218,6 +218,12 @@ inline bool isSwapInstruction(Instruction _inst) return Instruction::SWAP1 <= _inst && _inst <= Instruction::SWAP16; } +/// @returns true if the instruction is a LOG +inline bool isLogInstruction(Instruction _inst) +{ + return Instruction::LOG0 <= _inst && _inst <= Instruction::LOG4; +} + /// @returns the number of PUSH Instruction _inst inline unsigned getPushNumber(Instruction _inst) { @@ -236,6 +242,12 @@ inline unsigned getSwapNumber(Instruction _inst) return (byte)_inst - unsigned(Instruction::SWAP1) + 1; } +/// @returns the number of LOG Instruction _inst +inline unsigned getLogNumber(Instruction _inst) +{ + return (byte)_inst - unsigned(Instruction::LOG0); +} + /// @returns the PUSH<_number> instruction inline Instruction pushInstruction(unsigned _number) { diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp index f4e49655..dc536f77 100644 --- a/libjulia/backends/evm/EVMCodeTransform.cpp +++ b/libjulia/backends/evm/EVMCodeTransform.cpp @@ -545,11 +545,13 @@ void CodeTransform::expectDeposit(int _deposit, int _oldHeight) const void CodeTransform::checkStackHeight(void const* _astElement) const { solAssert(m_info.stackHeightInfo.count(_astElement), "Stack height for AST element not found."); + int stackHeightInAnalysis = m_info.stackHeightInfo.at(_astElement); + int stackHeightInCodegen = m_assembly.stackHeight() - m_stackAdjustment; solAssert( - m_info.stackHeightInfo.at(_astElement) == m_assembly.stackHeight() - m_stackAdjustment, + stackHeightInAnalysis == stackHeightInCodegen, "Stack height mismatch between analysis and code generation phase: Analysis: " + - to_string(m_info.stackHeightInfo.at(_astElement)) + + to_string(stackHeightInAnalysis) + " code gen: " + - to_string(m_assembly.stackHeight() - m_stackAdjustment) + to_string(stackHeightInCodegen) ); } diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp index 8a576e2e..81de3c43 100644 --- a/libsolidity/analysis/ReferencesResolver.cpp +++ b/libsolidity/analysis/ReferencesResolver.cpp @@ -246,6 +246,8 @@ void ReferencesResolver::endVisit(ArrayTypeName const& _typeName) RationalNumberType const* lengthType = dynamic_cast<RationalNumberType const*>(lengthTypeGeneric.get()); if (!lengthType || !lengthType->mobileType()) fatalTypeError(length->location(), "Invalid array length, expected integer literal or constant expression."); + else if (lengthType->isZero()) + fatalTypeError(length->location(), "Array with zero length specified."); else if (lengthType->isFractional()) fatalTypeError(length->location(), "Array with fractional length specified."); else if (lengthType->isNegative()) diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index c97ee657..fd72bf41 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -1276,13 +1276,13 @@ u256 RationalNumberType::literalValue(Literal const*) const else { auto fixed = fixedPointType(); - solAssert(fixed, ""); + solAssert(fixed, "Rational number cannot be represented as fixed point type."); int fractionalDigits = fixed->fractionalDigits(); shiftedValue = m_value.numerator() * boost::multiprecision::pow(bigint(10), fractionalDigits) / m_value.denominator(); } // we ignore the literal and hope that the type was correctly determined - solAssert(shiftedValue <= u256(-1), "Integer constant too large."); + solAssert(shiftedValue <= u256(-1), "Number constant too large."); solAssert(shiftedValue >= -(bigint(1) << 255), "Number constant too small."); if (m_value >= rational(0)) diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 9a0110cf..0f2c0f56 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -565,18 +565,10 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio // We assume that returndatacopy, returndatasize and staticcall are either all available // or all not available. solAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), ""); + // Similarly we assume bitwise shifting and create2 go together. + solAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), ""); - if (_instr == solidity::Instruction::CREATE2) - m_errorReporter.warning( - _location, - "The \"" + - boost::to_lower_copy(instructionInfo(_instr).name) - + "\" instruction is not supported by the VM version \"" + - "" + m_evmVersion.name() + - "\" you are currently compiling for. " + - "It will be interpreted as an invalid instruction on this VM." - ); - else if (( + if (( _instr == solidity::Instruction::RETURNDATACOPY || _instr == solidity::Instruction::RETURNDATASIZE || _instr == solidity::Instruction::STATICCALL @@ -593,7 +585,8 @@ void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocatio else if (( _instr == solidity::Instruction::SHL || _instr == solidity::Instruction::SHR || - _instr == solidity::Instruction::SAR + _instr == solidity::Instruction::SAR || + _instr == solidity::Instruction::CREATE2 ) && !m_evmVersion.hasBitwiseShifting()) m_errorReporter.warning( _location, diff --git a/libsolidity/interface/EVMVersion.h b/libsolidity/interface/EVMVersion.h index b68e1f4e..657727ac 100644 --- a/libsolidity/interface/EVMVersion.h +++ b/libsolidity/interface/EVMVersion.h @@ -75,6 +75,7 @@ public: bool supportsReturndata() const { return *this >= byzantium(); } bool hasStaticCall() const { return *this >= byzantium(); } bool hasBitwiseShifting() const { return *this >= constantinople(); } + bool hasCreate2() const { return *this >= constantinople(); } /// Whether we have to retain the costs for the call opcode itself (false), /// or whether we can just forward easily all remaining gas (true). diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index af8465fc..b2e2b63b 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -396,7 +396,7 @@ BOOST_AUTO_TEST_CASE(returndatasize_as_variable) {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"} }); if (!dev::test::Options::get().evmVersion().supportsReturndata()) - expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible"))); + expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"returndatasize\" instruction is only available for Byzantium-compatible VMs."))); CHECK_ALLOW_MULTI(text, expectations); } @@ -407,10 +407,12 @@ BOOST_AUTO_TEST_CASE(create2_as_variable) )"; // This needs special treatment, because the message mentions the EVM version, // so cannot be run via isoltest. - CHECK_ALLOW_MULTI(text, (std::vector<std::pair<Error::Type, std::string>>{ - {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"}, - {Error::Type::Warning, "The \"create2\" instruction is not supported by the VM version"}, - })); + vector<pair<Error::Type, std::string>> expectations(vector<pair<Error::Type, std::string>>{ + {Error::Type::Warning, "Variable is shadowed in inline assembly by an instruction of the same name"} + }); + if (!dev::test::Options::get().evmVersion().hasCreate2()) + expectations.emplace_back(make_pair(Error::Type::Warning, std::string("\"create2\" instruction is only available for Constantinople-compatible VMs."))); + CHECK_ALLOW_MULTI(text, expectations); } BOOST_AUTO_TEST_CASE(getter_is_memory_type) diff --git a/test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol b/test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol new file mode 100644 index 00000000..fd8f3078 --- /dev/null +++ b/test/libsolidity/syntaxTests/array/length/fixed_size_multidim_zero_length.sol @@ -0,0 +1,15 @@ +contract C { + function a() public pure returns(int[0][500] memory) {} + function b() public pure returns(uint[0][500] memory) {} + function c() public pure returns(byte[0][500] memory) {} + function d() public pure returns(bytes32[0][500] memory) {} + function e() public pure returns(bytes[0][500] memory) {} + function e() public pure returns(string[0][500] memory) {} +} +// ---- +// TypeError: (52-53): Array with zero length specified. +// TypeError: (111-112): Array with zero length specified. +// TypeError: (170-171): Array with zero length specified. +// TypeError: (232-233): Array with zero length specified. +// TypeError: (292-293): Array with zero length specified. +// TypeError: (353-354): Array with zero length specified. diff --git a/test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol b/test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol new file mode 100644 index 00000000..b38939e3 --- /dev/null +++ b/test/libsolidity/syntaxTests/array/length/fixed_size_zero_length.sol @@ -0,0 +1,15 @@ +contract C { + int[0] a; + uint[0] b; + byte[0] c; + bytes32[0] d; + bytes[0] e; + string[0] f; +} +// ---- +// TypeError: (19-20): Array with zero length specified. +// TypeError: (32-33): Array with zero length specified. +// TypeError: (45-46): Array with zero length specified. +// TypeError: (61-62): Array with zero length specified. +// TypeError: (75-76): Array with zero length specified. +// TypeError: (90-91): Array with zero length specified. diff --git a/test/libsolidity/syntaxTests/array/length/parentheses.sol b/test/libsolidity/syntaxTests/array/length/parentheses.sol index 40f55ad6..8dbcc0a4 100644 --- a/test/libsolidity/syntaxTests/array/length/parentheses.sol +++ b/test/libsolidity/syntaxTests/array/length/parentheses.sol @@ -21,5 +21,5 @@ contract C { uint[((2) + 1) + 1] a12; uint[(2 + 1) + ((1))] a13; uint[(((2) + 1)) + (((1)))] a14; - uint[((((2) + 1)) + (((1))))%1] a15; + uint[((((3) + 1)) + (((1))))%2] a15; } diff --git a/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol b/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol index 9181222e..9adf6f12 100644 --- a/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol +++ b/test/libsolidity/syntaxTests/parsing/arrays_in_storage.sol @@ -1,6 +1,6 @@ contract c { uint[10] a; uint[] a2; - struct x { uint[2**20] b; y[0] c; } + struct x { uint[2**20] b; y[1] c; } struct y { uint d; mapping(uint=>x)[] e; } } |