diff options
39 files changed, 225 insertions, 303 deletions
diff --git a/docs/grammar.txt b/docs/grammar.txt index 09e492f3..b38b7ffa 100644 --- a/docs/grammar.txt +++ b/docs/grammar.txt @@ -88,7 +88,6 @@ Expression = | Expression '||' Expression | Expression '?' Expression ':' Expression | Expression ('=' | '|=' | '^=' | '&=' | '<<=' | '>>=' | '+=' | '-=' | '*=' | '/=' | '%=') Expression - | Expression? (',' Expression) | PrimaryExpression PrimaryExpression = Identifier @@ -96,6 +95,7 @@ PrimaryExpression = Identifier | NumberLiteral | HexLiteral | StringLiteral + | TupleExpression | ElementaryTypeNameExpression ExpressionList = Expression ( ',' Expression )* @@ -120,6 +120,9 @@ Identifier = [a-zA-Z_$] [a-zA-Z_$0-9]* HexNumber = '0x' [0-9a-fA-F]+ DecimalNumber = [0-9]+ +TupleExpression = '(' ( Expression ( ',' Expression )* )? ')' + | '[' ( Expression ( ',' Expression )* )? ']' + ElementaryTypeNameExpression = ElementaryTypeName ElementaryTypeName = 'address' | 'bool' | 'string' | 'var' diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst index 993e2c18..450b0286 100644 --- a/docs/solidity-by-example.rst +++ b/docs/solidity-by-example.rst @@ -94,7 +94,7 @@ of votes. // called incorrectly. But watch out, this // will currently also consume all provided gas // (this is planned to change in the future). - require((msg.sender == chairperson) && !voters[voter].voted); + require((msg.sender == chairperson) && !voters[voter].voted && (voters[voter].weight == 0)); voters[voter].weight = 1; } @@ -165,7 +165,7 @@ of votes. } } } - + // Calls winningProposal() function to get the index // of the winner contained in the proposals array and then // returns the name of the winner @@ -273,7 +273,7 @@ activate themselves. // If the bid is not higher, send the // money back. require(msg.value > highestBid); - + if (highestBidder != 0) { // Sending back the money by simply using // highestBidder.send(highestBid) is a security risk @@ -296,7 +296,7 @@ activate themselves. // before `send` returns. pendingReturns[msg.sender] = 0; - if (!msg.sender.send(amount)) { + if (!msg.sender.send(amount)) { // No need to call throw here, just reset the amount owing pendingReturns[msg.sender] = amount; return false; diff --git a/libdevcore/Assertions.h b/libdevcore/Assertions.h index e54b9d55..729ffb05 100644 --- a/libdevcore/Assertions.h +++ b/libdevcore/Assertions.h @@ -25,7 +25,6 @@ #pragma once #include "Exceptions.h" -#include "debugbreak.h" namespace dev { @@ -38,37 +37,6 @@ namespace dev #define ETH_FUNC __func__ #endif -#define asserts(A) ::dev::assertAux(A, #A, __LINE__, __FILE__, ETH_FUNC) -#define assertsEqual(A, B) ::dev::assertEqualAux(A, B, #A, #B, __LINE__, __FILE__, ETH_FUNC) - -inline bool assertAux(bool _a, char const* _aStr, unsigned _line, char const* _file, char const* _func) -{ - bool ret = _a; - if (!ret) - { - std::cerr << "Assertion failed:" << _aStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; -#if ETH_DEBUG - debug_break(); -#endif - } - return !ret; -} - -template<class A, class B> -inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char const* _bStr, unsigned _line, char const* _file, char const* _func) -{ - bool ret = _a == _b; - if (!ret) - { - std::cerr << "Assertion failed: " << _aStr << " == " << _bStr << " [func=" << _func << ", line=" << _line << ", file=" << _file << "]" << std::endl; - std::cerr << " Fail equality: " << _a << "==" << _b << std::endl; -#if ETH_DEBUG - debug_break(); -#endif - } - return !ret; -} - /// Assertion that throws an exception containing the given description if it is not met. /// Use it as assertThrow(1 == 1, ExceptionType, "Mathematics is wrong."); /// Do NOT supply an exception object as the second parameter. @@ -86,6 +54,4 @@ inline bool assertEqualAux(A const& _a, B const& _b, char const* _aStr, char con } \ while (false) -using errinfo_comment = boost::error_info<struct tag_comment, std::string>; - } diff --git a/libdevcore/Common.h b/libdevcore/Common.h index dc981ff6..c5b09a80 100644 --- a/libdevcore/Common.h +++ b/libdevcore/Common.h @@ -76,8 +76,6 @@ using byte = uint8_t; #define DEV_QUOTED_HELPER(s) #s #define DEV_QUOTED(s) DEV_QUOTED_HELPER(s) -#define DEV_IGNORE_EXCEPTIONS(X) try { X; } catch (...) {} - namespace dev { diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp index 8dbcb00a..52829455 100644 --- a/libdevcore/CommonIO.cpp +++ b/libdevcore/CommonIO.cpp @@ -30,11 +30,11 @@ #include <termios.h> #endif #include <boost/filesystem.hpp> -#include "Exceptions.h" +#include "Assertions.h" + using namespace std; using namespace dev; - template <typename _T> inline _T contentsGeneric(std::string const& _file) { @@ -78,13 +78,24 @@ void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDe if (!fs::exists(p.parent_path())) { fs::create_directories(p.parent_path()); - DEV_IGNORE_EXCEPTIONS(fs::permissions(p.parent_path(), fs::owner_all)); + try + { + fs::permissions(p.parent_path(), fs::owner_all); + } + catch (...) + { + } } ofstream s(_file, ios::trunc | ios::binary); s.write(reinterpret_cast<char const*>(_data.data()), _data.size()); - if (!s) - BOOST_THROW_EXCEPTION(FileError() << errinfo_comment("Could not write to file: " + _file)); - DEV_IGNORE_EXCEPTIONS(fs::permissions(_file, fs::owner_read|fs::owner_write)); + assertThrow(s, FileError, "Could not write to file: " + _file); + try + { + fs::permissions(_file, fs::owner_read|fs::owner_write); + } + catch (...) + { + } } } diff --git a/libdevcore/Exceptions.h b/libdevcore/Exceptions.h index 37cdbed9..4817e9e3 100644 --- a/libdevcore/Exceptions.h +++ b/libdevcore/Exceptions.h @@ -56,9 +56,5 @@ DEV_SIMPLE_EXCEPTION(FileError); // error information to be added to exceptions using errinfo_invalidSymbol = boost::error_info<struct tag_invalidSymbol, char>; using errinfo_comment = boost::error_info<struct tag_comment, std::string>; -using errinfo_required = boost::error_info<struct tag_required, bigint>; -using errinfo_got = boost::error_info<struct tag_got, bigint>; -using errinfo_required_h256 = boost::error_info<struct tag_required_h256, h256>; -using errinfo_got_h256 = boost::error_info<struct tag_get_h256, h256>; } diff --git a/libdevcore/debugbreak.h b/libdevcore/debugbreak.h deleted file mode 100644 index f8838a5f..00000000 --- a/libdevcore/debugbreak.h +++ /dev/null @@ -1,128 +0,0 @@ -/* Copyright (c) 2013, Scott Tsai - * - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DEBUG_BREAK_H -#define DEBUG_BREAK_H - -#if defined(_MSC_VER) || defined(__MINGW32__) - -#define debug_break __debugbreak - -#else - -#include <signal.h> -#include <unistd.h> -#include <sys/syscall.h> - -#ifdef __cplusplus -extern "C" { -#endif - -enum { - /* gcc optimizers consider code after __builtin_trap() dead. - * Making __builtin_trap() unsuitable for breaking into the debugger */ - DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP = 0, -}; - -#if defined(__i386__) || defined(__x86_64__) -enum { HAVE_TRAP_INSTRUCTION = 1, }; -__attribute__((gnu_inline, always_inline)) -static void __inline__ trap_instruction(void) -{ - __asm__ volatile("int $0x03"); -} -#elif defined(__thumb__) -enum { HAVE_TRAP_INSTRUCTION = 1, }; -/* FIXME: handle __THUMB_INTERWORK__ */ -__attribute__((gnu_inline, always_inline)) -static void __inline__ trap_instruction(void) -{ - /* See 'arm-linux-tdep.c' in GDB source. - * Both instruction sequences below works. */ -#if 1 - /* 'eabi_linux_thumb_le_breakpoint' */ - __asm__ volatile(".inst 0xde01"); -#else - /* 'eabi_linux_thumb2_le_breakpoint' */ - __asm__ volatile(".inst.w 0xf7f0a000"); -#endif - - /* Known problem: - * After a breakpoint hit, can't stepi, step, or continue in GDB. - * 'step' stuck on the same instruction. - * - * Workaround: a new GDB command, - * 'debugbreak-step' is defined in debugbreak-gdb.py - * that does: - * (gdb) set $instruction_len = 2 - * (gdb) tbreak *($pc + $instruction_len) - * (gdb) jump *($pc + $instruction_len) - */ -} -#elif defined(__arm__) && !defined(__thumb__) -enum { HAVE_TRAP_INSTRUCTION = 1, }; -__attribute__((gnu_inline, always_inline)) -static void __inline__ trap_instruction(void) -{ - /* See 'arm-linux-tdep.c' in GDB source, - * 'eabi_linux_arm_le_breakpoint' */ - __asm__ volatile(".inst 0xe7f001f0"); - /* Has same known problem and workaround - * as Thumb mode */ -} -#elif defined(ETH_EMSCRIPTEN) -enum { HAVE_TRAP_INSTRUCTION = 1, }; -__attribute__((gnu_inline, always_inline)) -static void __inline__ trap_instruction(void) -{ - asm("debugger"); -} -#else -enum { HAVE_TRAP_INSTRUCTION = 0, }; -#endif - -__attribute__((gnu_inline, always_inline)) -static void __inline__ debug_break(void) -{ - if (HAVE_TRAP_INSTRUCTION) { - trap_instruction(); - } else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) { - /* raises SIGILL on Linux x86{,-64}, to continue in gdb: - * (gdb) handle SIGILL stop nopass - * */ - __builtin_trap(); - } else { - raise(SIGTRAP); - } -} - -#ifdef __cplusplus -} -#endif - -#endif - -#endif diff --git a/libevmasm/Assembly.cpp b/libevmasm/Assembly.cpp index 92a4c2a4..27199b7b 100644 --- a/libevmasm/Assembly.cpp +++ b/libevmasm/Assembly.cpp @@ -55,21 +55,15 @@ void Assembly::append(Assembly const& _a) m_subs += _a.m_subs; for (auto const& lib: _a.m_libraries) m_libraries.insert(lib); - - assert(!_a.m_baseDeposit); - assert(!_a.m_totalDeposit); } void Assembly::append(Assembly const& _a, int _deposit) { - if (_deposit > _a.m_deposit) - BOOST_THROW_EXCEPTION(InvalidDeposit()); - else - { - append(_a); - while (_deposit++ < _a.m_deposit) - append(Instruction::POP); - } + assertThrow(_deposit <= _a.m_deposit, InvalidDeposit, ""); + + append(_a); + while (_deposit++ < _a.m_deposit) + append(Instruction::POP); } unsigned Assembly::bytesRequired(unsigned subTagSize) const diff --git a/libevmasm/Assembly.h b/libevmasm/Assembly.h index 13d82e1a..0d40abcf 100644 --- a/libevmasm/Assembly.h +++ b/libevmasm/Assembly.h @@ -85,16 +85,10 @@ public: AssemblyItem const& back() const { return m_items.back(); } std::string backString() const { return m_items.size() && m_items.back().type() == PushString ? m_strings.at((h256)m_items.back().data()) : std::string(); } - void onePath() { if (asserts(!m_totalDeposit && !m_baseDeposit)) BOOST_THROW_EXCEPTION(InvalidDeposit()); m_baseDeposit = m_deposit; m_totalDeposit = INT_MAX; } - void otherPath() { donePath(); m_totalDeposit = m_deposit; m_deposit = m_baseDeposit; } - void donePaths() { donePath(); m_totalDeposit = m_baseDeposit = 0; } - void ignored() { m_baseDeposit = m_deposit; } - void endIgnored() { m_deposit = m_baseDeposit; m_baseDeposit = 0; } - void injectStart(AssemblyItem const& _i); int deposit() const { return m_deposit; } - void adjustDeposit(int _adjustment) { m_deposit += _adjustment; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } - void setDeposit(int _deposit) { m_deposit = _deposit; if (asserts(m_deposit >= 0)) BOOST_THROW_EXCEPTION(InvalidDeposit()); } + void adjustDeposit(int _adjustment) { m_deposit += _adjustment; assertThrow(m_deposit >= 0, InvalidDeposit, ""); } + void setDeposit(int _deposit) { m_deposit = _deposit; assertThrow(m_deposit >= 0, InvalidDeposit, ""); } /// Changes the source location used for each appended item. void setSourceLocation(SourceLocation const& _location) { m_currentSourceLocation = _location; } @@ -121,7 +115,6 @@ protected: /// returns the replaced tags. std::map<u256, u256> optimiseInternal(bool _enable, bool _isCreation, size_t _runs); - void donePath() { if (m_totalDeposit != INT_MAX && m_totalDeposit != m_deposit) BOOST_THROW_EXCEPTION(InvalidDeposit()); } unsigned bytesRequired(unsigned subTagSize) const; private: @@ -144,8 +137,6 @@ protected: mutable std::vector<size_t> m_tagPositionsInBytecode; int m_deposit = 0; - int m_baseDeposit = 0; - int m_totalDeposit = 0; SourceLocation m_currentSourceLocation; }; diff --git a/libjulia/backends/evm/EVMAssembly.cpp b/libjulia/backends/evm/EVMAssembly.cpp index daca2393..7ec26957 100644 --- a/libjulia/backends/evm/EVMAssembly.cpp +++ b/libjulia/backends/evm/EVMAssembly.cpp @@ -22,7 +22,7 @@ #include <libevmasm/Instruction.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> using namespace std; using namespace dev; diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp index b231ecec..8f12bc25 100644 --- a/libjulia/backends/evm/EVMCodeTransform.cpp +++ b/libjulia/backends/evm/EVMCodeTransform.cpp @@ -23,7 +23,7 @@ #include <libsolidity/inlineasm/AsmAnalysisInfo.h> #include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <boost/range/adaptor/reversed.hpp> diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp index 9f37bc65..1329ec9b 100644 --- a/liblll/CodeFragment.cpp +++ b/liblll/CodeFragment.cpp @@ -192,7 +192,13 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) { if (_t.size() != 2) error<IncorrectParameterCount>(); - m_asm.append(CodeFragment::compile(contentsString(firstAsString()), _s).m_asm); + string fileName = firstAsString(); + if (fileName.empty()) + error<InvalidName>("Empty file name provided"); + string contents = contentsString(fileName); + if (contents.empty()) + error<InvalidName>(std::string("File not found (or empty): ") + fileName); + m_asm.append(CodeFragment::compile(contents, _s).m_asm); } else if (us == "SET") { @@ -439,15 +445,21 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) int minDep = min(code[1].m_asm.deposit(), code[2].m_asm.deposit()); m_asm.append(code[0].m_asm); - auto pos = m_asm.appendJumpI(); - m_asm.onePath(); + auto mainBranch = m_asm.appendJumpI(); + + /// The else branch. + int startDeposit = m_asm.deposit(); m_asm.append(code[2].m_asm, minDep); auto end = m_asm.appendJump(); - m_asm.otherPath(); - m_asm << pos.tag(); + int deposit = m_asm.deposit(); + m_asm.setDeposit(startDeposit); + + /// The main branch. + m_asm << mainBranch.tag(); m_asm.append(code[1].m_asm, minDep); m_asm << end.tag(); - m_asm.donePaths(); + if (m_asm.deposit() != deposit) + error<InvalidDeposit>(); } else if (us == "WHEN" || us == "UNLESS") { @@ -458,11 +470,8 @@ void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s) if (us == "WHEN") m_asm.append(Instruction::ISZERO); auto end = m_asm.appendJumpI(); - m_asm.onePath(); - m_asm.otherPath(); m_asm.append(code[1].m_asm, 0); m_asm << end.tag(); - m_asm.donePaths(); } else if (us == "WHILE" || us == "UNTIL") { diff --git a/liblll/CompilerState.cpp b/liblll/CompilerState.cpp index c22242a3..5d38bb8c 100644 --- a/liblll/CompilerState.cpp +++ b/liblll/CompilerState.cpp @@ -49,13 +49,15 @@ void CompilerState::populateStandard() "(def 'allgas (- (gas) 21))" "(def 'send (to value) (call allgas to value 0 0 0 0))" "(def 'send (gaslimit to value) (call gaslimit to value 0 0 0 0))" - "(def 'msg (gaslimit to value data datasize outsize) { (set x outsize) (set y (alloc @32)) (call gaslimit to value data datasize @0 @32) @0 })" + // NOTE: in this macro, memory location 0 is set in order to force msize to be at least 32 bytes. + "(def 'msg (gaslimit to value data datasize outsize) { [0]:0 [0]:(msize) (call gaslimit to value data datasize @0 outsize) @0 })" "(def 'msg (gaslimit to value data datasize) { (call gaslimit to value data datasize 0 32) @0 })" "(def 'msg (gaslimit to value data) { [0]:data (msg gaslimit to value 0 32) })" "(def 'msg (to value data) { [0]:data (msg allgas to value 0 32) })" "(def 'msg (to data) { [0]:data (msg allgas to 0 0 32) })" - "(def 'create (value code) { [0]:(msize) (create value @0 (lll code @0)) })" - "(def 'create (code) { [0]:(msize) (create 0 @0 (lll code @0)) })" + // NOTE: in the create macros, memory location 0 is set in order to force msize to be at least 32 bytes. + "(def 'create (value code) { [0]:0 [0]:(msize) (create value @0 (lll code @0)) })" + "(def 'create (code) { [0]:0 [0]:(msize) (create 0 @0 (lll code @0)) })" "(def 'sha3 (loc len) (keccak256 loc len))" "(def 'sha3 (val) { [0]:val (sha3 0 32) })" "(def 'sha3pair (a b) { [0]:a [32]:b (sha3 0 64) })" @@ -65,7 +67,7 @@ void CompilerState::populateStandard() "(def 'makeperm (name pos) { (def name (sload pos)) (def name (v) (sstore pos v)) } )" "(def 'permcount 0)" "(def 'perm (name) { (makeperm name permcount) (def 'permcount (+ permcount 1)) } )" - "(def 'ecrecover (r s v hash) { [0] r [32] s [64] v [96] hash (msg allgas 1 0 0 128) })" + "(def 'ecrecover (hash v r s) { [0] hash [32] v [64] r [96] s (msg allgas 1 0 0 128) })" "(def 'sha256 (data datasize) (msg allgas 2 0 data datasize))" "(def 'ripemd160 (data datasize) (msg allgas 3 0 data datasize))" "(def 'sha256 (val) { [0]:val (sha256 0 32) })" diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 03112d2d..40dfa348 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -20,10 +20,8 @@ * Solidity abstract syntax tree. */ -#include <libsolidity/interface/Utils.h> #include <libsolidity/ast/AST.h> #include <libsolidity/ast/ASTVisitor.h> -#include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/AST_accept.h> #include <libdevcore/SHA3.h> diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index ba1d0589..83572692 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -29,7 +29,6 @@ #include <boost/noncopyable.hpp> #include <libevmasm/SourceLocation.h> #include <libevmasm/Instruction.h> -#include <libsolidity/interface/Utils.h> #include <libsolidity/ast/ASTForward.h> #include <libsolidity/parsing/Token.h> #include <libsolidity/ast/Types.h> diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index 4ad1f962..a90debb2 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -24,7 +24,6 @@ #include <boost/algorithm/string/join.hpp> #include <libdevcore/UTF8.h> #include <libsolidity/ast/AST.h> -#include <libsolidity/interface/Exceptions.h> #include <libsolidity/inlineasm/AsmData.h> #include <libsolidity/inlineasm/AsmPrinter.h> diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index c2de5c48..27114c2a 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -26,7 +26,6 @@ #include <stack> #include <libsolidity/ast/ASTVisitor.h> #include <libsolidity/interface/Exceptions.h> -#include <libsolidity/interface/Utils.h> #include <libsolidity/ast/ASTAnnotations.h> #include <json/json.h> diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index cfee041e..bd3346f9 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -22,7 +22,6 @@ #include <libsolidity/ast/Types.h> -#include <libsolidity/interface/Utils.h> #include <libsolidity/ast/AST.h> #include <libdevcore/CommonIO.h> diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp index 6a641b02..67ca22f1 100644 --- a/libsolidity/codegen/ArrayUtils.cpp +++ b/libsolidity/codegen/ArrayUtils.cpp @@ -25,7 +25,7 @@ #include <libsolidity/codegen/CompilerContext.h> #include <libsolidity/codegen/CompilerUtils.h> #include <libsolidity/ast/Types.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <libsolidity/codegen/LValue.h> using namespace std; diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index 25154bc0..03bba80c 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -32,6 +32,7 @@ #include <libsolidity/codegen/CompilerUtils.h> #include <libsolidity/codegen/LValue.h> #include <libevmasm/GasMeter.h> + using namespace std; namespace dev diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h index d0a8ac15..3b8cf1c6 100644 --- a/libsolidity/codegen/ExpressionCompiler.h +++ b/libsolidity/codegen/ExpressionCompiler.h @@ -28,7 +28,7 @@ #include <libevmasm/SourceLocation.h> #include <libsolidity/ast/ASTVisitor.h> #include <libsolidity/codegen/LValue.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> namespace dev { namespace eth diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 2891ec95..b0d044ae 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -26,7 +26,6 @@ #include <libsolidity/inlineasm/AsmAnalysisInfo.h> #include <libsolidity/interface/ErrorReporter.h> -#include <libsolidity/interface/Utils.h> #include <boost/range/adaptor/reversed.hpp> #include <boost/algorithm/string.hpp> diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index 0d06fedd..062ff453 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -22,7 +22,7 @@ #include <libsolidity/inlineasm/AsmPrinter.h> #include <libsolidity/inlineasm/AsmData.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <boost/algorithm/string.hpp> #include <boost/algorithm/string/replace.hpp> diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp index 3bef9cec..5b3174b8 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libsolidity/inlineasm/AsmScopeFiller.cpp @@ -25,7 +25,7 @@ #include <libsolidity/inlineasm/AsmAnalysisInfo.h> #include <libsolidity/interface/ErrorReporter.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <boost/range/adaptor/reversed.hpp> diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index b09108b0..8be2c8dd 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -481,12 +481,12 @@ Json::Value const& CompilerStack::natspec(Contract const& _contract, Documentati return *(*doc); } -Json::Value CompilerStack::functionHashes(ContractDefinition const& _contract) +Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const { - Json::Value functionHashes(Json::objectValue); - for (auto const& it: _contract.interfaceFunctions()) - functionHashes[it.second->externalSignature()] = toHex(it.first.ref()); - return functionHashes; + Json::Value methodIdentifiers(Json::objectValue); + for (auto const& it: contractDefinition(_contractName).interfaceFunctions()) + methodIdentifiers[it.second->externalSignature()] = toHex(it.first.ref()); + return methodIdentifiers; } string const& CompilerStack::onChainMetadata(string const& _contractName) const diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h index 3250429b..f7435f0e 100644 --- a/libsolidity/interface/CompilerStack.h +++ b/libsolidity/interface/CompilerStack.h @@ -178,7 +178,8 @@ public: /// Can be one of 4 types defined at @c DocumentationType Json::Value const& natspec(std::string const& _contractName, DocumentationType _type) const; - Json::Value functionHashes(ContractDefinition const& _contract); + /// @returns a JSON representing a map of method identifiers (hashes) to function names. + Json::Value methodIdentifiers(std::string const& _contractName) const; std::string const& onChainMetadata(std::string const& _contractName) const; void useMetadataLiteralSources(bool _metadataLiteralSources) { m_metadataLiteralSources = _metadataLiteralSources; } @@ -190,9 +191,6 @@ public: Scanner const& scanner(std::string const& _sourceName = "") const; /// @returns the parsed source unit with the supplied name. SourceUnit const& ast(std::string const& _sourceName = "") const; - /// @returns the parsed contract with the supplied name. Throws an exception if the contract - /// does not exist. - ContractDefinition const& contractDefinition(std::string const& _contractName) const; /// Helper function for logs printing. Do only use in error cases, it's quite expensive. /// line and columns are numbered starting from 1 with following order: @@ -257,6 +255,10 @@ private: Contract const& contract(std::string const& _contractName = "") const; Source const& source(std::string const& _sourceName = "") const; + /// @returns the parsed contract with the supplied name. Throws an exception if the contract + /// does not exist. + ContractDefinition const& contractDefinition(std::string const& _contractName) const; + std::string createOnChainMetadata(Contract const& _contract) const; std::string computeSourceMapping(eth::AssemblyItems const& _items) const; Json::Value const& contractABI(Contract const&) const; diff --git a/libsolidity/interface/Exceptions.cpp b/libsolidity/interface/Exceptions.cpp index c09180de..deee92aa 100644 --- a/libsolidity/interface/Exceptions.cpp +++ b/libsolidity/interface/Exceptions.cpp @@ -21,7 +21,6 @@ */ #include <libsolidity/interface/Exceptions.h> -#include <libsolidity/interface/Utils.h> using namespace std; using namespace dev; diff --git a/libsolidity/interface/Exceptions.h b/libsolidity/interface/Exceptions.h index 0803d8cc..5fdb8f11 100644 --- a/libsolidity/interface/Exceptions.h +++ b/libsolidity/interface/Exceptions.h @@ -25,6 +25,7 @@ #include <string> #include <utility> #include <libdevcore/Exceptions.h> +#include <libdevcore/Assertions.h> #include <libevmasm/SourceLocation.h> namespace dev @@ -39,6 +40,16 @@ struct InternalCompilerError: virtual Exception {}; struct FatalError: virtual Exception {}; struct UnimplementedFeatureError: virtual Exception{}; +/// Assertion that throws an InternalCompilerError containing the given description if it is not met. +#define solAssert(CONDITION, DESCRIPTION) \ + assertThrow(CONDITION, ::dev::solidity::InternalCompilerError, DESCRIPTION) + +#define solUnimplementedAssert(CONDITION, DESCRIPTION) \ + assertThrow(CONDITION, ::dev::solidity::UnimplementedFeatureError, DESCRIPTION) + +#define solUnimplemented(DESCRIPTION) \ + solUnimplementedAssert(false, DESCRIPTION) + class Error: virtual public Exception { public: diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index d5dbaa46..2e5005b8 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -115,14 +115,6 @@ StringMap createSourceList(Json::Value const& _input) return sources; } -Json::Value methodIdentifiers(ContractDefinition const& _contract) -{ - Json::Value methodIdentifiers(Json::objectValue); - for (auto const& it: _contract.interfaceFunctions()) - methodIdentifiers[it.second->externalSignature()] = toHex(it.first.ref()); - return methodIdentifiers; -} - Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkReferences) { Json::Value ret(Json::objectValue); @@ -404,7 +396,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.streamAssembly(tmp, contractName, createSourceList(_input), false); evmData["assembly"] = tmp.str(); evmData["legacyAssembly"] = m_compilerStack.streamAssembly(tmp, contractName, createSourceList(_input), true); - evmData["methodIdentifiers"] = methodIdentifiers(m_compilerStack.contractDefinition(contractName)); + evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName); evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); evmData["bytecode"] = collectEVMObject( diff --git a/libsolidity/interface/Utils.h b/libsolidity/interface/Utils.h deleted file mode 100644 index 0027759c..00000000 --- a/libsolidity/interface/Utils.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - This file is part of solidity. - - solidity is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - solidity is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with solidity. If not, see <http://www.gnu.org/licenses/>. -*/ -/** - * @author Christian <c@ethdev.com> - * @date 2014 - * Solidity Utilities. - */ - -#pragma once - -#include <libdevcore/Assertions.h> -#include <libsolidity/interface/Exceptions.h> - -namespace dev -{ -namespace solidity -{ -struct InternalCompilerError; -struct UnimplementedFeatureError; -} -} - -/// Assertion that throws an InternalCompilerError containing the given description if it is not met. -#define solAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::dev::solidity::InternalCompilerError, DESCRIPTION) - -#define solUnimplementedAssert(CONDITION, DESCRIPTION) \ - assertThrow(CONDITION, ::dev::solidity::UnimplementedFeatureError, DESCRIPTION) - -#define solUnimplemented(DESCRIPTION) \ - solUnimplementedAssert(false, DESCRIPTION) diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp index 0d23f9c3..a35bfd29 100644 --- a/libsolidity/interface/Version.cpp +++ b/libsolidity/interface/Version.cpp @@ -24,7 +24,7 @@ #include <string> #include <libdevcore/CommonData.h> #include <libdevcore/Common.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <solidity/BuildInfo.h> using namespace dev; diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp index cd6c1d8a..0409de72 100644 --- a/libsolidity/parsing/DocStringParser.cpp +++ b/libsolidity/parsing/DocStringParser.cpp @@ -1,7 +1,7 @@ #include <libsolidity/parsing/DocStringParser.h> #include <libsolidity/interface/ErrorReporter.h> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <boost/range/irange.hpp> #include <boost/range/algorithm.hpp> diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp index 0e60fd0b..fdca23ea 100644 --- a/libsolidity/parsing/Scanner.cpp +++ b/libsolidity/parsing/Scanner.cpp @@ -52,7 +52,7 @@ #include <algorithm> #include <tuple> -#include <libsolidity/interface/Utils.h> +#include <libsolidity/interface/Exceptions.h> #include <libsolidity/parsing/Scanner.h> using namespace std; diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h index 9a557ebd..39c0eff9 100644 --- a/libsolidity/parsing/Token.h +++ b/libsolidity/parsing/Token.h @@ -43,7 +43,6 @@ #pragma once #include <libdevcore/Common.h> -#include <libsolidity/interface/Utils.h> #include <libsolidity/interface/Exceptions.h> #include <libdevcore/UndefMacros.h> diff --git a/scripts/bytecodecompare/prepare_report.py b/scripts/bytecodecompare/prepare_report.py index 5a770981..427724b7 100755 --- a/scripts/bytecodecompare/prepare_report.py +++ b/scripts/bytecodecompare/prepare_report.py @@ -6,7 +6,7 @@ import subprocess import json solc = sys.argv[1] -report = open("report.txt", "w") +report = open("report.txt", "wb") for optimize in [False, True]: for f in sorted(glob.glob("*.sol")): diff --git a/scripts/bytecodecompare/storebytecode.bat b/scripts/bytecodecompare/storebytecode.bat index aa829d20..e64e9276 100644 --- a/scripts/bytecodecompare/storebytecode.bat +++ b/scripts/bytecodecompare/storebytecode.bat @@ -27,15 +27,16 @@ cd bytecode ..\scripts\isolate_tests.py ..\test\ ..\scripts\bytecodecompare\prepare_report.py ..\build\solc\%CONFIGURATION%\solc.exe -git clone --depth 2 git@github.com:ethereum/solidity-test-bytecode.git +REM Send to stdout instead of stderr to not confuse powershell +git clone --depth 2 git@github.com:ethereum/solidity-test-bytecode.git 2>&1 cd solidity-test-bytecode git config user.name "travis" git config user.email "chris@ethereum.org" -git clean -f -d -x +git clean -f -d -x 2>&1 if not exist %DIRECTORY% mkdir %DIRECTORY% set REPORT=%DIRECTORY%/windows.txt cp ../report.txt %REPORT% git add %REPORT% git commit -a -m "Added report." -git push origin +git push origin 2>&1 diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e37922c6..0dbedd3c 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -281,9 +281,10 @@ void CommandLineInterface::handleSignatureHashes(string const& _contract) if (!m_args.count(g_argSignatureHashes)) return; + Json::Value methodIdentifiers = m_compiler->methodIdentifiers(_contract); string out; - for (auto const& it: m_compiler->contractDefinition(_contract).interfaceFunctions()) - out += toHex(it.first.ref()) + ": " + it.second->externalSignature() + "\n"; + for (auto const& name: methodIdentifiers.getMemberNames()) + out += methodIdentifiers[name].asString() + ": " + name + "\n"; if (m_args.count(g_argOutputDir)) createFile(m_compiler->filesystemFriendlyName(_contract) + ".signatures", out); @@ -889,7 +890,7 @@ void CommandLineInterface::handleCombinedJSON() contractData[g_strSrcMapRuntime] = map ? *map : ""; } if (requests.count(g_strSignatureHashes)) - contractData[g_strSignatureHashes] = m_compiler->functionHashes(m_compiler->contractDefinition(contractName)); + contractData[g_strSignatureHashes] = m_compiler->methodIdentifiers(contractName); if (requests.count(g_strNatspecDev)) contractData[g_strNatspecDev] = dev::jsonCompactPrint(m_compiler->natspec(contractName, DocumentationType::NatspecDev)); if (requests.count(g_strNatspecUser)) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index c01c8061..5165f984 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -192,7 +192,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback contractData["runtimeBytecode"] = compiler.runtimeObject(contractName).toHex(); contractData["opcodes"] = solidity::disassemble(compiler.object(contractName).bytecode); contractData["metadata"] = compiler.onChainMetadata(contractName); - contractData["functionHashes"] = compiler.functionHashes(compiler.contractDefinition(contractName)); + contractData["functionHashes"] = compiler.methodIdentifiers(contractName); contractData["gasEstimates"] = estimateGas(compiler, contractName); auto sourceMap = compiler.sourceMapping(contractName); contractData["srcmap"] = sourceMap ? *sourceMap : ""; diff --git a/test/liblll/EndToEndTest.cpp b/test/liblll/EndToEndTest.cpp index 3928ff45..02d024a4 100644 --- a/test/liblll/EndToEndTest.cpp +++ b/test/liblll/EndToEndTest.cpp @@ -57,6 +57,68 @@ BOOST_AUTO_TEST_CASE(panic) BOOST_REQUIRE(m_output.empty()); } +BOOST_AUTO_TEST_CASE(when) +{ + char const* sourceCode = R"( + (returnlll + (seq + (when (= (calldatasize) 0) (return 1)) + (when (!= (calldatasize) 0) (return 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(unless) +{ + char const* sourceCode = R"( + (returnlll + (seq + (unless (!= (calldatasize) 0) (return 1)) + (unless (= (calldatasize) 0) (return 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(conditional_literal) +{ + char const* sourceCode = R"( + (returnlll + (seq + (return (if (= (calldatasize) 0) 1 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(conditional) +{ + char const* sourceCode = R"( + (returnlll + (seq + (if (= (calldatasize) 0) (return 1) (return 2)))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + +BOOST_AUTO_TEST_CASE(conditional_seq) +{ + char const* sourceCode = R"( + (returnlll + (seq + (return (if (= (calldatasize) 0) { 0 2 1 } { 0 1 2 })))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(u256(2))); + BOOST_CHECK(callFallback() == toBigEndian(u256(1))); +} + BOOST_AUTO_TEST_CASE(exp_operator_const) { char const* sourceCode = R"( @@ -304,6 +366,51 @@ BOOST_AUTO_TEST_CASE(keccak256_32bytes) fromHex("b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"))); } +BOOST_AUTO_TEST_CASE(msg_six_args) +{ + char const* sourceCode = R"( + (returnlll + (seq + (when (= 0 (calldatasize)) + (seq + (mstore 0x40 1) + (def 'outsize 0x20) + (return (msg 1000 (address) 42 0x40 0x20 outsize) outsize))) + (when (= 1 (calldataload 0x00)) + (return (callvalue))))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42))); +} + +BOOST_AUTO_TEST_CASE(create_1_arg) +{ + char const* sourceCode = R"( + (returnlll + (seq + (call allgas + (create (returnlll (return 42))) + 0 0 0 0x00 0x20) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs(u256(42))); +} + +BOOST_AUTO_TEST_CASE(create_2_args) +{ + char const* sourceCode = R"( + (returnlll + (seq + (call allgas + (create 42 (returnlll (return (balance (address))))) + 0 0 0 0x00 0x20) + (return 0x00 0x20))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallbackWithValue(42) == encodeArgs(u256(42))); +} + BOOST_AUTO_TEST_CASE(sha3_two_args) { char const* sourceCode = R"( @@ -328,6 +435,25 @@ BOOST_AUTO_TEST_CASE(sha3_one_arg) fromHex("b10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf6"))); } +BOOST_AUTO_TEST_CASE(ecrecover) +{ + char const* sourceCode = R"( + (returnlll + (return + (ecrecover + ; Hash of 'hello world' + 0x47173285a8d7341e5e972fc677286384f802f8ef42a5ec5f03bbfa254cb01fad + ; v = 1 + 27 + 0x1c + ; r + 0xdebaaa0cddb321b2dcaaf846d39605de7b97e77ba6106587855b9106cb104215 + ; s + 0x61a22d94fa8b8a687ff9c911c844d1c016d1a685a9166858f9c7c1bc85128aca))) + )"; + compileAndRun(sourceCode); + BOOST_CHECK(callFallback() == encodeArgs(fromHex("0x8743523d96a1b2cbe0c6909653a56da18ed484af"))); +} + BOOST_AUTO_TEST_CASE(shift_left) { char const* sourceCode = R"( |