aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/common-patterns.rst8
-rw-r--r--docs/control-structures.rst60
-rw-r--r--docs/index.rst3
-rw-r--r--docs/miscellaneous.rst2
-rw-r--r--docs/types.rst9
-rw-r--r--docs/units-and-global-variables.rst2
-rw-r--r--libsolidity/codegen/CompilerContext.cpp48
-rw-r--r--libsolidity/codegen/CompilerContext.h9
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp47
-rw-r--r--libsolidity/inlineasm/AsmStack.cpp22
-rw-r--r--libsolidity/inlineasm/AsmStack.h8
-rw-r--r--libsolidity/parsing/Scanner.cpp35
-rw-r--r--libsolidity/parsing/Scanner.h1
-rw-r--r--libsolidity/parsing/Token.h9
-rwxr-xr-xscripts/install_deps.sh32
-rw-r--r--solc/jsonCompiler.cpp4
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp43
-rw-r--r--test/libsolidity/SolidityScanner.cpp36
18 files changed, 344 insertions, 34 deletions
diff --git a/docs/common-patterns.rst b/docs/common-patterns.rst
index 422e2758..322be3ef 100644
--- a/docs/common-patterns.rst
+++ b/docs/common-patterns.rst
@@ -82,13 +82,13 @@ restrictions highly readable.
// refunded, but only after the function body.
// This is dangerous, because if the function
// uses `return` explicitly, this will not be
- // done!
+ // done! This behavior will be fixed in Version 0.4.0.
modifier costs(uint _amount) {
if (msg.value < _amount)
throw;
_
if (msg.value > _amount)
- msg.sender.send(_amount - msg.value);
+ msg.sender.send(msg.value - _amount);
}
function forceOwnerChange(address _newOwner)
@@ -163,7 +163,9 @@ function finishes.
the code in the transitionNext modifier
can be skipped if the function itself uses
return. If you want to do that, make sure
- to call nextStage manually from those functions.
+ to call nextStage manually from those functions.
+ With version 0.4.0 (unreleased), modifier code
+ will run even if the function explicitly returns.
::
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index e03d8d6a..a6daccac 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -10,7 +10,7 @@ Control Structures
Most of the control structures from C/JavaScript are available in Solidity
except for ``switch`` and ``goto``. So
there is: ``if``, ``else``, ``while``, ``for``, ``break``, ``continue``, ``return``, ``? :``, with
-the usual semantics known from C / JavaScript.
+the usual semantics known from C or JavaScript.
Parentheses can *not* be omitted for conditionals, but curly brances can be omitted
around single-statement bodies.
@@ -82,13 +82,15 @@ parentheses at the end perform the actual call.
that the called contract can change state variables of the calling contract
via its functions. Write your functions in a way that, for example, calls to
external functions happen after any changes to state variables in your contract
- so your contract is not vulnerable to a recursive call exploit.
+ so your contract is not vulnerable to a reentrancy exploit.
Named Calls and Anonymous Function Parameters
---------------------------------------------
-Function call arguments can also be given by name, in any order, and the names
-of unused parameters (especially return parameters) can be omitted.
+Function call arguments can also be given by name, in any order,
+if they are enclosed in ``{ }`` as can be seen in the following
+example. The argument list has to coincide by name with the list of
+parameters from the function declaration, but can be in arbitrary order.
::
@@ -99,12 +101,60 @@ of unused parameters (especially return parameters) can be omitted.
// named arguments
f({value: 2, key: 3});
}
+ }
+
+Omitted Function Parameter Names
+--------------------------------
+
+The names of unused parameters (especially return parameters) can be omitted.
+Those names will still be present on the stack, but they are inaccessible.
- // omitted parameters
+::
+
+ contract C {
+ // omitted name for parameter
function func(uint k, uint) returns(uint) {
return k;
}
}
+
+
+.. index:: ! new, contracts;creating
+
+.. _creating-contracts:
+
+Creating Contracts via new
+==========================
+
+A contract can create a new contract using the ``new`` keyword. The full
+code of the contract to be created has to be known and thus recursive
+creation-dependencies are now possible.
+
+::
+
+ contract D {
+ uint x;
+ function D(uint a) {
+ x = a;
+ }
+ }
+ contract C {
+ D d = new D(4); // will be executed as part of C's constructor
+
+ function createD(uint arg) {
+ D newD = new D(arg);
+ }
+
+ function createAndEndowD(uint arg, uint amount) {
+ // Send ether along with the creation
+ D newD = (new D).value(amount)(arg);
+ }
+ }
+
+As seen in the example, it is possible to forward Ether to the creation,
+but it is not possible to limit the amount of gas. If the creation fails
+(due to out-of-stack, not enough balance or other problems), an exception
+is thrown.
Order of Evaluation of Expressions
==================================
diff --git a/docs/index.rst b/docs/index.rst
index 5ca5c4a9..4b3ace89 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -56,6 +56,9 @@ Available Solidity Integrations
* `Vim Solidity <https://github.com/tomlion/vim-solidity/>`_
Plugin for the Vim editor providing syntax highlighting.
+* `Vim Syntastic <https://github.com/scrooloose/syntastic>`_
+ Plugin for the Vim editor providing compile checking.
+
Discontinued:
* `Mix IDE <https://github.com/ethereum/mix/>`_
diff --git a/docs/miscellaneous.rst b/docs/miscellaneous.rst
index ca0cf593..804d69ef 100644
--- a/docs/miscellaneous.rst
+++ b/docs/miscellaneous.rst
@@ -286,7 +286,7 @@ Global Variables
- ``sha3(...) returns (bytes32)``: compute the Ethereum-SHA-3 (KECCAK-256) hash of the (tightly packed) arguments
- ``sha256(...) returns (bytes32)``: compute the SHA-256 hash of the (tightly packed) arguments
- ``ripemd160(...) returns (bytes20)``: compute the RIPEMD-160 hash of the (tightly packed) arguments
-- ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature
+- ``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``: recover address associated with the public key from elliptic curve signature, return zero on error
- ``addmod(uint x, uint y, uint k) returns (uint)``: compute ``(x + y) % k`` where the addition is performed with arbitrary precision and does not wrap around at ``2**256``
- ``mulmod(uint x, uint y, uint k) returns (uint)``: compute ``(x * y) % k`` where the multiplication is performed with arbitrary precision and does not wrap around at ``2**256``
- ``this`` (current contract's type): the current contract, explicitly convertible to ``address``
diff --git a/docs/types.rst b/docs/types.rst
index 12a35aaf..31f6b53d 100644
--- a/docs/types.rst
+++ b/docs/types.rst
@@ -218,6 +218,15 @@ String literals are written with either double or single-quotes (``"foo"`` or ``
String literals support escape characters, such as ``\n``, ``\xNN`` and ``\uNNNN``. ``\xNN`` takes a hex value and inserts the appropriate byte, while ``\uNNNN`` takes a Unicode codepoint and inserts an UTF-8 sequence.
+.. index:: literal, bytes
+
+Hexadecimal Literals
+--------------------
+
+Hexademical Literals are prefixed with the keyword ``hex`` and are enclosed in double or single-quotes (``hex"001122FF"``). Their content must be a hexadecimal string and their value will be the binary representation of those values.
+
+Hexademical Literals behave like String Literals and have the same convertibility restrictions.
+
.. index:: enum
.. _enums:
diff --git a/docs/units-and-global-variables.rst b/docs/units-and-global-variables.rst
index 62b9158d..d1d578ed 100644
--- a/docs/units-and-global-variables.rst
+++ b/docs/units-and-global-variables.rst
@@ -95,7 +95,7 @@ Mathematical and Cryptographic Functions
``ripemd160(...) returns (bytes20)``:
compute RIPEMD-160 hash of the (tightly packed) arguments
``ecrecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) returns (address)``:
- recover the address associated with the public key from elliptic curve signature
+ recover the address associated with the public key from elliptic curve signature or return zero on error
In the above, "tightly packed" means that the arguments are concatenated without padding.
This means that the following are all identical::
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index c1dc8dfb..3ac5bd3c 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -23,9 +23,12 @@
#include <libsolidity/codegen/CompilerContext.h>
#include <utility>
#include <numeric>
+#include <boost/algorithm/string/replace.hpp>
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/interface/Version.h>
+#include <libsolidity/inlineasm/AsmData.h>
+#include <libsolidity/inlineasm/AsmStack.h>
using namespace std;
@@ -172,6 +175,51 @@ void CompilerContext::resetVisitedNodes(ASTNode const* _node)
updateSourceLocation();
}
+void CompilerContext::appendInlineAssembly(
+ string const& _assembly,
+ vector<string> const& _localVariables,
+ map<string, string> const& _replacements
+)
+{
+ string replacedAssembly;
+ string const* assembly = &_assembly;
+ if (!_replacements.empty())
+ {
+ replacedAssembly = _assembly;
+ for (auto const& replacement: _replacements)
+ replacedAssembly = boost::algorithm::replace_all_copy(replacedAssembly, replacement.first, replacement.second);
+ assembly = &replacedAssembly;
+ }
+
+ unsigned startStackHeight = stackHeight();
+ auto identifierAccess = [&](
+ assembly::Identifier const& _identifier,
+ eth::Assembly& _assembly,
+ assembly::CodeGenerator::IdentifierContext _context
+ ) {
+ auto it = std::find(_localVariables.begin(), _localVariables.end(), _identifier.name);
+ if (it == _localVariables.end())
+ return false;
+ unsigned stackDepth = _localVariables.end() - it;
+ int stackDiff = _assembly.deposit() - startStackHeight + stackDepth;
+ if (stackDiff < 1 || stackDiff > 16)
+ BOOST_THROW_EXCEPTION(
+ CompilerError() <<
+ errinfo_comment("Stack too deep, try removing local variables.")
+ );
+ if (_context == assembly::CodeGenerator::IdentifierContext::RValue)
+ _assembly.append(dupInstruction(stackDiff));
+ else
+ {
+ _assembly.append(swapInstruction(stackDiff));
+ _assembly.append(Instruction::POP);
+ }
+ return true;
+ };
+
+ solAssert(assembly::InlineAssemblyStack().parseAndAssemble(*assembly, m_asm, identifierAccess), "");
+}
+
void CompilerContext::injectVersionStampIntoSub(size_t _subIndex)
{
eth::Assembly& sub = m_asm.sub(_subIndex);
diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h
index a56335ce..0c1500b0 100644
--- a/libsolidity/codegen/CompilerContext.h
+++ b/libsolidity/codegen/CompilerContext.h
@@ -132,6 +132,15 @@ public:
CompilerContext& operator<<(u256 const& _value) { m_asm.append(_value); return *this; }
CompilerContext& operator<<(bytes const& _data) { m_asm.append(_data); return *this; }
+ /// Appends inline assembly. @a _replacements are string-matching replacements that are performed
+ /// prior to parsing the inline assembly.
+ /// @param _localVariables assigns stack positions to variables with the last one being the stack top
+ void appendInlineAssembly(
+ std::string const& _assembly,
+ std::vector<std::string> const& _localVariables = std::vector<std::string>(),
+ std::map<std::string, std::string> const& _replacements = std::map<std::string, std::string>{}
+ );
+
/// Prepends "PUSH <compiler version number> POP"
void injectVersionStampIntoSub(size_t _subIndex);
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 1d574556..1f93cf8c 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -23,6 +23,7 @@
#include <utility>
#include <numeric>
#include <boost/range/adaptor/reversed.hpp>
+#include <boost/algorithm/string/replace.hpp>
#include <libdevcore/Common.h>
#include <libdevcore/SHA3.h>
#include <libsolidity/ast/AST.h>
@@ -533,6 +534,9 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
else
m_context << u256(0);
m_context << Instruction::CREATE;
+ // Check if zero (out of stack or not enough balance).
+ m_context << Instruction::DUP1 << Instruction::ISZERO;
+ m_context.appendConditionalJumpTo(m_context.errorTag());
if (function.valueSet())
m_context << swapInstruction(1) << Instruction::POP;
break;
@@ -1445,6 +1449,19 @@ void ExpressionCompiler::appendExternalFunctionCall(
argumentTypes.push_back(_arguments[i]->annotation().type);
}
+ if (funKind == FunctionKind::ECRecover)
+ {
+ // Clears 32 bytes of currently free memory and advances free memory pointer.
+ // Output area will be "start of input area" - 32.
+ // The reason is that a failing ECRecover cannot be detected, it will just return
+ // zero bytes (which we cannot detect).
+ solAssert(0 < retSize && retSize <= 32, "");
+ utils().fetchFreeMemoryPointer();
+ m_context << Instruction::DUP1 << u256(0) << Instruction::MSTORE;
+ m_context << u256(32) << Instruction::ADD;
+ utils().storeFreeMemoryPointer();
+ }
+
// Copy function identifier to memory.
utils().fetchFreeMemoryPointer();
if (!_functionType.isBareCall() || manualFunctionId)
@@ -1453,7 +1470,7 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().storeInMemoryDynamic(IntegerType(8 * CompilerUtils::dataStartOffset), false);
}
// If the function takes arbitrary parameters, copy dynamic length data in place.
- // Move argumenst to memory, will not update the free memory pointer (but will update the memory
+ // Move arguments to memory, will not update the free memory pointer (but will update the memory
// pointer on the stack).
utils().encodeToMemory(
argumentTypes,
@@ -1471,12 +1488,24 @@ void ExpressionCompiler::appendExternalFunctionCall(
// function identifier [unless bare]
// contract address
- // Output data will replace input data.
+ // Output data will replace input data, unless we have ECRecover (then, output
+ // area will be 32 bytes just before input area).
// put on stack: <size of output> <memory pos of output> <size of input> <memory pos of input>
m_context << u256(retSize);
- utils().fetchFreeMemoryPointer();
- m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB;
- m_context << Instruction::DUP2;
+ utils().fetchFreeMemoryPointer(); // This is the start of input
+ if (funKind == FunctionKind::ECRecover)
+ {
+ // In this case, output is 32 bytes before input and has already been cleared.
+ m_context << u256(32) << Instruction::DUP2 << Instruction::SUB << Instruction::SWAP1;
+ // Here: <input end> <output size> <outpos> <input pos>
+ m_context << Instruction::DUP1 << Instruction::DUP5 << Instruction::SUB;
+ m_context << Instruction::SWAP1;
+ }
+ else
+ {
+ m_context << Instruction::DUP1 << Instruction::DUP4 << Instruction::SUB;
+ m_context << Instruction::DUP2;
+ }
// CALL arguments: outSize, outOff, inSize, inOff (already present up to here)
// [value,] addr, gas (stack top)
@@ -1539,6 +1568,14 @@ void ExpressionCompiler::appendExternalFunctionCall(
utils().loadFromMemoryDynamic(IntegerType(160), false, true, false);
utils().convertType(IntegerType(160), FixedBytesType(20));
}
+ else if (funKind == FunctionKind::ECRecover)
+ {
+ // Output is 32 bytes before input / free mem pointer.
+ // Failing ecrecover cannot be detected, so we clear output before the call.
+ m_context << u256(32);
+ utils().fetchFreeMemoryPointer();
+ m_context << Instruction::SUB << Instruction::MLOAD;
+ }
else if (!_functionType.returnParameterTypes().empty())
{
utils().fetchFreeMemoryPointer();
diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp
index c891678b..11c6e28f 100644
--- a/libsolidity/inlineasm/AsmStack.cpp
+++ b/libsolidity/inlineasm/AsmStack.cpp
@@ -24,6 +24,7 @@
#include <memory>
#include <libevmasm/Assembly.h>
#include <libevmasm/SourceLocation.h>
+#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/inlineasm/AsmParser.h>
#include <libsolidity/inlineasm/AsmCodeGen.h>
@@ -32,7 +33,7 @@ using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::assembly;
-bool InlineAssemblyStack::parse(const std::shared_ptr<Scanner>& _scanner)
+bool InlineAssemblyStack::parse(shared_ptr<Scanner> const& _scanner)
{
m_parserResult = make_shared<Block>();
Parser parser(m_errors);
@@ -49,3 +50,22 @@ eth::Assembly InlineAssemblyStack::assemble()
return codeGen.assemble();
}
+bool InlineAssemblyStack::parseAndAssemble(
+ string const& _input,
+ eth::Assembly& _assembly,
+ CodeGenerator::IdentifierAccess const& _identifierAccess
+)
+{
+ ErrorList errors;
+ auto scanner = make_shared<Scanner>(CharStream(_input), "--CODEGEN--");
+ auto parserResult = Parser(errors).parse(scanner);
+ if (!errors.empty())
+ return false;
+
+ CodeGenerator(*parserResult, errors).assemble(_assembly, _identifierAccess);
+
+ // At this point, the assembly might be messed up, but we should throw an
+ // internal compiler error anyway.
+ return errors.empty();
+}
+
diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h
index 8a860e46..521f5fe7 100644
--- a/libsolidity/inlineasm/AsmStack.h
+++ b/libsolidity/inlineasm/AsmStack.h
@@ -25,6 +25,7 @@
#include <string>
#include <functional>
#include <libsolidity/interface/Exceptions.h>
+#include <libsolidity/inlineasm/AsmCodeGen.h>
namespace dev
{
@@ -47,6 +48,13 @@ public:
bool parse(std::shared_ptr<Scanner> const& _scanner);
eth::Assembly assemble();
+ /// Parse and assemble a string in one run - for use in Solidity code generation itself.
+ bool parseAndAssemble(
+ std::string const& _input,
+ eth::Assembly& _assembly,
+ CodeGenerator::IdentifierAccess const& _identifierAccess = CodeGenerator::IdentifierAccess()
+ );
+
ErrorList const& errors() const { return m_errors; }
private:
diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp
index d730210a..603f3e42 100644
--- a/libsolidity/parsing/Scanner.cpp
+++ b/libsolidity/parsing/Scanner.cpp
@@ -591,7 +591,23 @@ void Scanner::scanToken()
break;
default:
if (isIdentifierStart(m_char))
+ {
tie(token, m, n) = scanIdentifierOrKeyword();
+
+ // Special case for hexademical literals
+ if (token == Token::Hex)
+ {
+ // reset
+ m = 0;
+ n = 0;
+
+ // Special quoted hex string must follow
+ if (m_char == '"' || m_char == '\'')
+ token = scanHexString();
+ else
+ token = Token::Illegal;
+ }
+ }
else if (isDecimalDigit(m_char))
token = scanNumber();
else if (skipWhitespace())
@@ -684,6 +700,25 @@ Token::Value Scanner::scanString()
return Token::StringLiteral;
}
+Token::Value Scanner::scanHexString()
+{
+ char const quote = m_char;
+ advance(); // consume quote
+ LiteralScope literal(this, LITERAL_TYPE_STRING);
+ while (m_char != quote && !isSourcePastEndOfInput() && !isLineTerminator(m_char))
+ {
+ char c = m_char;
+ if (!scanHexByte(c))
+ return Token::Illegal;
+ addLiteralChar(c);
+ }
+ if (m_char != quote)
+ return Token::Illegal;
+ literal.complete();
+ advance(); // consume quote
+ return Token::StringLiteral;
+}
+
void Scanner::scanDecimalDigits()
{
while (isDecimalDigit(m_char))
diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h
index 708adf8f..36cba112 100644
--- a/libsolidity/parsing/Scanner.h
+++ b/libsolidity/parsing/Scanner.h
@@ -203,6 +203,7 @@ private:
std::tuple<Token::Value, unsigned, unsigned> scanIdentifierOrKeyword();
Token::Value scanString();
+ Token::Value scanHexString();
Token::Value scanSingleLineDocComment();
Token::Value scanMultiLineDocComment();
/// Scans a slash '/' and depending on the characters returns the appropriate token
diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h
index 5ac7aedd..007baef4 100644
--- a/libsolidity/parsing/Token.h
+++ b/libsolidity/parsing/Token.h
@@ -141,6 +141,7 @@ namespace solidity
\
/* Keywords */ \
K(Anonymous, "anonymous", 0) \
+ K(As, "as", 0) \
K(Assembly, "assembly", 0) \
K(Break, "break", 0) \
K(Const, "constant", 0) \
@@ -154,6 +155,7 @@ namespace solidity
K(External, "external", 0) \
K(For, "for", 0) \
K(Function, "function", 0) \
+ K(Hex, "hex", 0) \
K(If, "if", 0) \
K(Indexed, "indexed", 0) \
K(Internal, "internal", 0) \
@@ -171,6 +173,7 @@ namespace solidity
K(Storage, "storage", 0) \
K(Struct, "struct", 0) \
K(Throw, "throw", 0) \
+ K(Using, "using", 0) \
K(Var, "var", 0) \
K(While, "while", 0) \
\
@@ -214,22 +217,24 @@ namespace solidity
T(Identifier, NULL, 0) \
\
/* Keywords reserved for future use. */ \
+ K(Abstract, "abstract", 0) \
K(After, "after", 0) \
- K(As, "as", 0) \
K(Case, "case", 0) \
K(Catch, "catch", 0) \
K(Final, "final", 0) \
K(In, "in", 0) \
K(Inline, "inline", 0) \
+ K(Interface, "interface", 0) \
K(Let, "let", 0) \
K(Match, "match", 0) \
K(Of, "of", 0) \
+ K(Payable, "payable", 0) \
K(Relocatable, "relocatable", 0) \
+ K(Static, "static", 0) \
K(Switch, "switch", 0) \
K(Try, "try", 0) \
K(Type, "type", 0) \
K(TypeOf, "typeof", 0) \
- K(Using, "using", 0) \
/* Illegal token - not able to scan. */ \
T(Illegal, "ILLEGAL", 0) \
\
diff --git a/scripts/install_deps.sh b/scripts/install_deps.sh
index bbf28d95..4fb948ed 100755
--- a/scripts/install_deps.sh
+++ b/scripts/install_deps.sh
@@ -1,7 +1,7 @@
-#!/usr/bin/env bash
+#!/usr/bin/env sh
#------------------------------------------------------------------------------
-# Bash script for installing pre-requisite packages for solidity on a
+# Shell script for installing pre-requisite packages for solidity on a
# variety of Linux and other UNIX-derived platforms.
#
# This is an "infrastucture-as-code" alternative to the manual build
@@ -12,17 +12,9 @@
# flow for all supported operating systems:
#
# - git clone --recursive
-# - ./install_deps.sh
+# - ./scripts/install_deps.sh
# - cmake && make
#
-# At the time of writing we are assuming that 'lsb_release' is present for all
-# Linux distros, which is not a valid assumption. We will need a variety of
-# approaches to actually get this working across all the distros which people
-# are using.
-#
-# See http://unix.stackexchange.com/questions/92199/how-can-i-reliably-get-the-operating-systems-name
-# for some more background on this common problem.
-#
# TODO - There is no support here yet for cross-builds in any form, only
# native builds. Expanding the functionality here to cover the mobile,
# wearable and SBC platforms covered by doublethink and EthEmbedded would
@@ -55,6 +47,19 @@
# Check for 'uname' and abort if it is not available.
uname -v > /dev/null 2>&1 || { echo >&2 "ERROR - solidity requires 'uname' to identify the platform."; exit 1; }
+# See http://unix.stackexchange.com/questions/92199/how-can-i-reliably-get-the-operating-systems-name
+detect_linux_distro() {
+ if [ $(command -v lsb_release) ]; then
+ DISTRO=$(lsb_release -is)
+ elif [ -f /etc/os-release ]; then
+ # extract 'foo' from NAME=foo, only on the line with NAME=foo
+ DISTRO=$(sed -n -e 's/^NAME="\(.*\)\"/\1/p' /etc/os-release)
+ else
+ DISTRO=''
+ fi
+ echo $DISTRO
+}
+
case $(uname -s) in
#------------------------------------------------------------------------------
@@ -124,7 +129,7 @@ case $(uname -s) in
#------------------------------------------------------------------------------
Linux)
- case $(lsb_release -is) in
+ case $(detect_linux_distro) in
#------------------------------------------------------------------------------
# Arch Linux
@@ -147,7 +152,7 @@ case $(uname -s) in
# Alpine Linux
#------------------------------------------------------------------------------
- Alpine)
+ "Alpine Linux")
#Alpine
echo "Installing solidity dependencies on Alpine Linux."
@@ -155,7 +160,6 @@ case $(uname -s) in
# See https://pkgs.alpinelinux.org/
apk update
- apk upgrade
apk add boost-dev build-base cmake jsoncpp-dev
;;
diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp
index 20112103..0a1b9a87 100644
--- a/solc/jsonCompiler.cpp
+++ b/solc/jsonCompiler.cpp
@@ -207,7 +207,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback
for (string const& contractName: compiler.contractNames())
{
Json::Value contractData(Json::objectValue);
- contractData["solidity_interface"] = compiler.solidityInterface(contractName);
+ contractData["solidityInterface"] = compiler.solidityInterface(contractName);
contractData["interface"] = compiler.interface(contractName);
contractData["bytecode"] = compiler.object(contractName).toHex();
contractData["runtimeBytecode"] = compiler.runtimeObject(contractName).toHex();
@@ -217,7 +217,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback
auto sourceMap = compiler.sourceMapping(contractName);
contractData["srcmap"] = sourceMap ? *sourceMap : "";
auto runtimeSourceMap = compiler.runtimeSourceMapping(contractName);
- contractData["srcmap-runtime"] = runtimeSourceMap ? *runtimeSourceMap : "";
+ contractData["srcmapRuntime"] = runtimeSourceMap ? *runtimeSourceMap : "";
ostringstream unused;
contractData["assembly"] = compiler.streamAssembly(unused, contractName, _sources, true);
output["contracts"][contractName] = contractData;
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index e4237c23..a1ab7700 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -6839,6 +6839,33 @@ BOOST_AUTO_TEST_CASE(skip_dynamic_types_for_structs)
BOOST_CHECK(callContractFunction("g()") == encodeArgs(u256(2), u256(6)));
}
+BOOST_AUTO_TEST_CASE(failed_create)
+{
+ char const* sourceCode = R"(
+ contract D { }
+ contract C {
+ uint public x;
+ function f(uint amount) returns (address) {
+ x++;
+ return (new D).value(amount)();
+ }
+ function stack(uint depth) returns (address) {
+ if (depth < 1024)
+ return this.stack(depth - 1);
+ else
+ return f(0);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 20, "C");
+ BOOST_CHECK(callContractFunction("f(uint256)", 20) != encodeArgs(u256(0)));
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("f(uint256)", 20) == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+ BOOST_CHECK(callContractFunction("stack(uint256)", 1023) == encodeArgs());
+ BOOST_CHECK(callContractFunction("x()") == encodeArgs(u256(1)));
+}
+
BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length)
{
char const* sourceCode = R"(
@@ -6853,6 +6880,22 @@ BOOST_AUTO_TEST_CASE(create_dynamic_array_with_zero_length)
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(7)));
}
+BOOST_AUTO_TEST_CASE(failing_ecrecover_invalid_input)
+{
+ // ecrecover should return zero for malformed input
+ // (v should be 27 or 28, not 1)
+ // Note that the precompile does not return zero but returns nothing.
+ char const* sourceCode = R"(
+ contract C {
+ function f() returns (address) {
+ return ecrecover(bytes32(uint(-1)), 1, 2, 3);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 0, "C");
+ BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(0)));
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/SolidityScanner.cpp b/test/libsolidity/SolidityScanner.cpp
index 624614d2..31b75f25 100644
--- a/test/libsolidity/SolidityScanner.cpp
+++ b/test/libsolidity/SolidityScanner.cpp
@@ -324,6 +324,42 @@ BOOST_AUTO_TEST_CASE(invalid_short_unicode_string_escape)
BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
}
+BOOST_AUTO_TEST_CASE(valid_hex_literal)
+{
+ Scanner scanner(CharStream("{ hex\"00112233FF\""));
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
+ BOOST_CHECK_EQUAL(scanner.next(), Token::StringLiteral);
+ BOOST_CHECK_EQUAL(scanner.currentLiteral(), std::string("\x00\x11\x22\x33\xFF", 5));
+}
+
+BOOST_AUTO_TEST_CASE(invalid_short_hex_literal)
+{
+ Scanner scanner(CharStream("{ hex\"00112233F\""));
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
+ BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_hex_literal_with_space)
+{
+ Scanner scanner(CharStream("{ hex\"00112233FF \""));
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
+ BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_hex_literal_with_wrong_quotes)
+{
+ Scanner scanner(CharStream("{ hex\"00112233FF'"));
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
+ BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
+}
+
+BOOST_AUTO_TEST_CASE(invalid_hex_literal_nonhex_string)
+{
+ Scanner scanner(CharStream("{ hex\"hello\""));
+ BOOST_CHECK_EQUAL(scanner.currentToken(), Token::LBrace);
+ BOOST_CHECK_EQUAL(scanner.next(), Token::Illegal);
+}
+
BOOST_AUTO_TEST_SUITE_END()