aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Changelog.md21
-rw-r--r--docs/control-structures.rst3
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp7
-rw-r--r--libsolidity/grammar.txt6
-rw-r--r--libsolidity/parsing/Token.h2
-rw-r--r--solc/CommandLineInterface.cpp40
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp20
7 files changed, 69 insertions, 30 deletions
diff --git a/Changelog.md b/Changelog.md
index 27f88cd2..2d9c6c31 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -7,13 +7,16 @@ enforce some safety features. The most important change is
Breaking Changes:
* Source files have to specify the compiler version they are
- compatible with using e.g. `pragma solidity ^0.4.0;` or
- `pragma solidity >=0.4.0 <0.4.8;`
- * Contracts that want to receive Ether have to implement a fallback
- function (contracts now throw if no fallback function is defined
- and no function matches the signature).
- * Failing contract creation through "new" throws now.
- * Throw on division / modulus by zero
+ compatible with using e.g. ``pragma solidity ^0.4.0;`` or
+ ``pragma solidity >=0.4.0 <0.4.8;``
+ * Functions that want to receive Ether have to specify the
+ new ``payable`` modifier (otherwise they throw).
+ * Contracts that want to receive Ether with a plain "send"
+ have to implement a fallback function with the ``payable``
+ modifier. Contracts now throw if no payable fallback
+ function is defined and no function matches the signature.
+ * Failing contract creation through "new" throws.
+ * Division / modulus by zero throws
* Function call throws if target contract does not have code
* Modifiers are required to contain ``_`` (use ``if (false) _`` as a workaround if needed).
* Modifiers: return does not skip part in modifier after ``_``
@@ -25,7 +28,7 @@ Breaking Changes:
* Moved (and reworked) standard library contracts from inside the compiler to github.com/ethereum/solidity/std
(``import "std";`` or ``import owned;`` do not work anymore).
* Confusing and undocumented keyword "after" was removed.
- * New reserved words: hex, payable, abstract, static, interface
+ * New reserved words: abstract, hex, interface, payable, pure, static, view
Features:
@@ -40,8 +43,10 @@ Bugfixes:
* JSON AST: nodes were added at wrong parent
* Why3 translator: crash fix for exponentiation
+ * Commandline Interface: linking libraries with underscores in their name.
* Type Checker: Fallback function cannot return data anymore.
* Code Generator: Fix crash when sha3() was used on unsupported types.
+ * Code Generator: Manually set gas stipend for .send(0).
Lots of changes to the documentation mainly by voluntary external contributors.
diff --git a/docs/control-structures.rst b/docs/control-structures.rst
index 0e430b6b..e6dfe4f6 100644
--- a/docs/control-structures.rst
+++ b/docs/control-structures.rst
@@ -523,7 +523,8 @@ The opcodes ``pushi`` and ``jumpdest`` cannot be used directly.
+-------------------------+------+-----------------------------------------------------------------+
| call(g, a, v, in, | | call contract at address a with input mem[in..(in+insize)) |
| insize, out, outsize) | | providing g gas and v wei and output area |
-| | | mem[out..(out+outsize)) returning 1 on error (out of gas) |
+| | | mem[out..(out+outsize)) returning 0 on error (eg. out of gas) |
+| | | and 1 on success |
+-------------------------+------+-----------------------------------------------------------------+
| callcode(g, a, v, in, | | identical to `call` but only use the code from a and stay |
| insize, out, outsize) | | in the context of the current contract otherwise |
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index 1cc4a50d..96ca4296 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -568,12 +568,17 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
break;
case Location::Send:
_functionCall.expression().accept(*this);
- m_context << u256(0); // do not send gas (there still is the stipend)
+ // Provide the gas stipend manually at first because we may send zero ether.
+ // Will be zeroed if we send more than zero ether.
+ m_context << u256(eth::GasCosts::callStipend);
arguments.front()->accept(*this);
utils().convertType(
*arguments.front()->annotation().type,
*function.parameterTypes().front(), true
);
+ // gas <- gas * !value
+ m_context << Instruction::SWAP1 << Instruction::DUP2;
+ m_context << Instruction::ISZERO << Instruction::MUL << Instruction::SWAP1;
appendExternalFunctionCall(
FunctionType(
TypePointers{},
diff --git a/libsolidity/grammar.txt b/libsolidity/grammar.txt
index 86df3db0..755cf281 100644
--- a/libsolidity/grammar.txt
+++ b/libsolidity/grammar.txt
@@ -43,9 +43,9 @@ StorageLocation = 'memory' | 'storage'
Block = '{' Statement* '}'
Statement = IfStatement | WhileStatement | ForStatement | Block |
( PlaceholderStatement | Continue | Break | Return |
- Throw | SimpleStatement | ExpressionStatement ) ';'
+ Throw | SimpleStatement ) ';'
-ExpressionStatement = Expression | VariableDefinition
+ExpressionStatement = Expression
IfStatement = 'if' '(' Expression ')' Statement ( 'else' Statement )?
WhileStatement = 'while' '(' Expression ')' Statement
PlaceholderStatement = '_'
@@ -79,7 +79,7 @@ Expression =
PrimaryExpression = Identifier | BooleanLiteral | NumberLiteral | StringLiteral
-FunctionCall = Identifier '(' Expression? ( ',' Expression )* ')'
+FunctionCall = ( PrimaryExpression | NewExpression | TypeName ) ( ( '.' Identifier ) | ( '[' Expression ']' ) )* '(' Expression? ( ',' Expression )* ')'
NewExpression = 'new' Identifier
MemberAccess = Expression '.' Identifier
IndexAccess = Expression '[' Expression? ']'
diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h
index cc85b610..2bf7419e 100644
--- a/libsolidity/parsing/Token.h
+++ b/libsolidity/parsing/Token.h
@@ -230,12 +230,14 @@ namespace solidity
K(Let, "let", 0) \
K(Match, "match", 0) \
K(Of, "of", 0) \
+ K(Pure, "pure", 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(View, "view", 0) \
/* Illegal token - not able to scan. */ \
T(Illegal, "ILLEGAL", 0) \
\
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index fbef56f0..f0a34632 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -778,37 +778,43 @@ void CommandLineInterface::actOnInput()
bool CommandLineInterface::link()
{
+ // Map from how the libraries will be named inside the bytecode to their addresses.
+ map<string, h160> librariesReplacements;
+ int const placeholderSize = 40; // 20 bytes or 40 hex characters
+ for (auto const& library: m_libraries)
+ {
+ string const& name = library.first;
+ // Library placeholders are 40 hex digits (20 bytes) that start and end with '__'.
+ // This leaves 36 characters for the library name, while too short library names are
+ // padded on the right with '_' and too long names are truncated.
+ string replacement = "__";
+ for (size_t i = 0; i < placeholderSize - 4; ++i)
+ replacement.push_back(i < name.size() ? name[i] : '_');
+ replacement += "__";
+ librariesReplacements[replacement] = library.second;
+ }
for (auto& src: m_sourceCodes)
{
auto end = src.second.end();
for (auto it = src.second.begin(); it != end;)
{
while (it != end && *it != '_') ++it;
- auto insertStart = it;
- while (it != end && *it == '_') ++it;
- auto nameStart = it;
- while (it != end && *it != '_') ++it;
- auto nameEnd = it;
- while (it != end && *it == '_') ++it;
- auto insertEnd = it;
-
- if (insertStart == end)
- break;
-
- if (insertEnd - insertStart != 40)
+ if (it == end) break;
+ if (end - it < placeholderSize)
{
- cerr << "Error in binary object file " << src.first << " at position " << (insertStart - src.second.begin()) << endl;
+ cerr << "Error in binary object file " << src.first << " at position " << (end - src.second.begin()) << endl;
return false;
}
- string name(nameStart, nameEnd);
- if (m_libraries.count(name))
+ string name(it, it + placeholderSize);
+ if (librariesReplacements.count(name))
{
- string hexStr(toHex(m_libraries.at(name).asBytes()));
- copy(hexStr.begin(), hexStr.end(), insertStart);
+ string hexStr(toHex(librariesReplacements.at(name).asBytes()));
+ copy(hexStr.begin(), hexStr.end(), it);
}
else
cerr << "Reference \"" << name << "\" in file \"" << src.first << "\" still unresolved." << endl;
+ it += placeholderSize;
}
}
return true;
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 1ecd7a2c..3c85d8a8 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -4625,6 +4625,26 @@ BOOST_AUTO_TEST_CASE(failing_send)
BOOST_REQUIRE(callContractFunction("callHelper(address)", c_helperAddress) == encodeArgs(true, 20));
}
+BOOST_AUTO_TEST_CASE(send_zero_ether)
+{
+ // Sending zero ether to a contract should still invoke the fallback function
+ // (it previously did not because the gas stipend was not provided by the EVM)
+ char const* sourceCode = R"(
+ contract Receiver {
+ function () payable {
+ }
+ }
+ contract Main {
+ function s() returns (bool) {
+ var r = new Receiver();
+ return r.send(0);
+ }
+ }
+ )";
+ compileAndRun(sourceCode, 20, "Main");
+ BOOST_REQUIRE(callContractFunction("s()") == encodeArgs(true));
+}
+
BOOST_AUTO_TEST_CASE(reusing_memory)
{
// Invoke some features that use memory and test that they do not interfere with each other.