aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt2
-rw-r--r--Changelog.md21
-rw-r--r--docs/bugs.json7
-rw-r--r--docs/bugs.rst2
-rw-r--r--docs/bugs_by_version.json49
-rw-r--r--docs/index.rst3
-rw-r--r--docs/installing-solidity.rst2
-rw-r--r--docs/solidity-by-example.rst12
-rw-r--r--libdevcore/CommonIO.cpp20
-rw-r--r--libdevcore/CommonIO.h5
-rw-r--r--liblll/CodeFragment.cpp44
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp23
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp16
-rw-r--r--libsolidity/analysis/TypeChecker.cpp6
-rw-r--r--libsolidity/ast/ASTForward.h1
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp11
-rw-r--r--libsolidity/formal/SMTChecker.cpp18
-rw-r--r--libsolidity/formal/SMTChecker.h4
-rw-r--r--libsolidity/formal/SMTLib2Interface.cpp9
-rw-r--r--libsolidity/formal/SMTLib2Interface.h8
-rw-r--r--libsolidity/formal/Z3Interface.cpp48
-rw-r--r--libsolidity/interface/CompilerStack.cpp37
-rw-r--r--libsolidity/interface/CompilerStack.h31
-rw-r--r--lllc/main.cpp36
-rwxr-xr-xscripts/test_emscripten.sh4
-rw-r--r--solc/CommandLineInterface.cpp28
-rw-r--r--test/ExecutionFramework.h67
-rw-r--r--test/RPCSession.cpp22
-rw-r--r--test/RPCSession.h1
-rw-r--r--test/contracts/AuctionRegistrar.cpp2
-rw-r--r--test/contracts/ContractInterface.h99
-rw-r--r--test/liblll/Compiler.cpp532
-rw-r--r--test/libsolidity/AnalysisFramework.cpp2
-rw-r--r--test/libsolidity/Assembly.cpp2
-rw-r--r--test/libsolidity/GasMeter.cpp14
-rw-r--r--test/libsolidity/SolidityABIJSON.cpp2
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp19
-rw-r--r--test/libsolidity/SolidityExecutionFramework.h2
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp65
-rw-r--r--test/libsolidity/SolidityNatspecJSON.cpp4
40 files changed, 1039 insertions, 241 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 537a9521..24bea3b3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -8,7 +8,7 @@ include(EthPolicy)
eth_policy()
# project name and version should be set after cmake_policy CMP0048
-set(PROJECT_VERSION "0.4.18")
+set(PROJECT_VERSION "0.4.19")
project(solidity VERSION ${PROJECT_VERSION})
option(SOLC_LINK_STATIC "Link solc executable statically on supported platforms" OFF)
diff --git a/Changelog.md b/Changelog.md
index acd9ee5e..45521f3e 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,8 +1,16 @@
-### 0.4.18 (unreleased)
+### 0.4.19 (unreleased)
+
+Features:
+ * Syntax Checker: Turn the usage of ``callcode`` into an error as experimental 0.5.0 feature.
+ * Type Checker: More detailed errors for invalid array lengths (such as division by zero).
+
+Bugfixes:
+
+### 0.4.18 (2017-10-18)
Features:
* Code Generator: Always use all available gas for calls as experimental 0.5.0 feature
- (previously, some amount was retained in order to work in pre-tangerine whistle
+ (previously, some amount was retained in order to work in pre-Tangerine-Whistle
EVM versions)
* Parser: Better error message for unexpected trailing comma in parameter lists.
* Standard JSON: Support the ``outputSelection`` field for selective compilation of supplied sources.
@@ -15,14 +23,17 @@ Features:
Bugfixes:
* Code Generator: Allocate one byte per memory byte array element instead of 32.
+ * Code Generator: Do not accept data with less than four bytes (truncated function
+ signature) for regular function calls - fallback function is invoked instead.
* Optimizer: Remove unused stack computation results.
* Parser: Fix source location of VariableDeclarationStatement.
+ * Type Checker: Allow ``gas`` in view functions.
+ * Type Checker: Do not mark event parameters as shadowing state variables.
+ * Type Checker: Prevent duplicate event declarations.
* Type Checker: Properly check array length and don't rely on an assertion in code generation.
* Type Checker: Properly support overwriting members inherited from ``address`` in a contract
(such as ``balance``, ``transfer``, etc.)
- * Type Checker: Prevent duplicate event declarations.
- * Type Checker: Do not mark event parameters as shadowing state variables.
- * Type Checker: Allow ``gas`` in view functions.
+ * Type Checker: Validate each number literal in tuple expressions even if they are not assigned from.
### 0.4.17 (2017-09-21)
diff --git a/docs/bugs.json b/docs/bugs.json
index ac322a48..c642793a 100644
--- a/docs/bugs.json
+++ b/docs/bugs.json
@@ -1,5 +1,12 @@
[
{
+ "name": "ZeroFunctionSelector",
+ "summary": "It is possible to craft the name of a function such that it is executed instead of the fallback function in very specific circumstances.",
+ "description": "If a function has a selector consisting only of zeros, is payable and part of a contract that does not have a fallback function and at most five external functions in total, this function is called instead of the fallback function if Ether is sent to the contract without data.",
+ "fixed": "0.4.18",
+ "severity": "very low"
+ },
+ {
"name": "DelegateCallReturnValue",
"summary": "The low-level .delegatecall() does not return the execution outcome, but converts the value returned by the functioned called to a boolean instead.",
"description": "The return value of the low-level .delegatecall() function is taken from a position in memory, where the call data or the return data resides. This value is interpreted as a boolean and put onto the stack. This means if the called function returns at least 32 zero bytes, .delegatecall() returns false even if the call was successuful.",
diff --git a/docs/bugs.rst b/docs/bugs.rst
index 55771a35..7629830d 100644
--- a/docs/bugs.rst
+++ b/docs/bugs.rst
@@ -48,7 +48,7 @@ fixed
publish
The date at which the bug became known publicly, optional
severity
- Severity of the bug: low, medium, high. Takes into account
+ Severity of the bug: very low, low, medium, high. Takes into account
discoverability in contract tests, likelihood of occurrence and
potential damage by exploits.
conditions
diff --git a/docs/bugs_by_version.json b/docs/bugs_by_version.json
index c3686ebf..cca45428 100644
--- a/docs/bugs_by_version.json
+++ b/docs/bugs_by_version.json
@@ -1,6 +1,7 @@
{
"0.1.0": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -17,6 +18,7 @@
},
"0.1.1": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -33,6 +35,7 @@
},
"0.1.2": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -49,6 +52,7 @@
},
"0.1.3": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -65,6 +69,7 @@
},
"0.1.4": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -81,6 +86,7 @@
},
"0.1.5": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -97,6 +103,7 @@
},
"0.1.6": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -114,6 +121,7 @@
},
"0.1.7": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -131,6 +139,7 @@
},
"0.2.0": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -148,6 +157,7 @@
},
"0.2.1": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -165,6 +175,7 @@
},
"0.2.2": {
"bugs": [
+ "ZeroFunctionSelector",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
"ConstantOptimizerSubtraction",
@@ -182,6 +193,7 @@
},
"0.3.0": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -199,6 +211,7 @@
},
"0.3.1": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -215,6 +228,7 @@
},
"0.3.2": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -231,6 +245,7 @@
},
"0.3.3": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -246,6 +261,7 @@
},
"0.3.4": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -261,6 +277,7 @@
},
"0.3.5": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -276,6 +293,7 @@
},
"0.3.6": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -289,6 +307,7 @@
},
"0.4.0": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -302,6 +321,7 @@
},
"0.4.1": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -315,6 +335,7 @@
},
"0.4.10": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -324,6 +345,7 @@
},
"0.4.11": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral"
@@ -332,6 +354,7 @@
},
"0.4.12": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
],
@@ -339,6 +362,7 @@
},
"0.4.13": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput"
],
@@ -346,24 +370,36 @@
},
"0.4.14": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue"
],
"released": "2017-07-31"
},
"0.4.15": {
- "bugs": [],
+ "bugs": [
+ "ZeroFunctionSelector"
+ ],
"released": "2017-08-08"
},
"0.4.16": {
- "bugs": [],
+ "bugs": [
+ "ZeroFunctionSelector"
+ ],
"released": "2017-08-24"
},
"0.4.17": {
- "bugs": [],
+ "bugs": [
+ "ZeroFunctionSelector"
+ ],
"released": "2017-09-21"
},
+ "0.4.18": {
+ "bugs": [],
+ "released": "2017-10-18"
+ },
"0.4.2": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -376,6 +412,7 @@
},
"0.4.3": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -387,6 +424,7 @@
},
"0.4.4": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -397,6 +435,7 @@
},
"0.4.5": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -408,6 +447,7 @@
},
"0.4.6": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -418,6 +458,7 @@
},
"0.4.7": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -427,6 +468,7 @@
},
"0.4.8": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
@@ -436,6 +478,7 @@
},
"0.4.9": {
"bugs": [
+ "ZeroFunctionSelector",
"DelegateCallReturnValue",
"ECRecoverMalformedInput",
"SkipEmptyStringLiteral",
diff --git a/docs/index.rst b/docs/index.rst
index cb093bd6..351f8ad7 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -61,6 +61,9 @@ Available Solidity Integrations
* `Solium <https://github.com/duaraghav8/Solium/>`_
A commandline linter for Solidity which strictly follows the rules prescribed by the `Solidity Style Guide <http://solidity.readthedocs.io/en/latest/style-guide.html>`_.
+
+* `Solhint <https://github.com/protofire/solhint>`_
+ Solidity linter that provides security, style guide and best practice rules for smart contract validation.
* `Visual Studio Code extension <http://juan.blanco.ws/solidity-contracts-in-visual-studio-code/>`_
Solidity plugin for Microsoft Visual Studio Code that includes syntax highlighting and the Solidity compiler.
diff --git a/docs/installing-solidity.rst b/docs/installing-solidity.rst
index 71607745..b660cf02 100644
--- a/docs/installing-solidity.rst
+++ b/docs/installing-solidity.rst
@@ -230,6 +230,8 @@ Or, on Windows:
Command-Line Build
------------------
+**Be sure to install External Dependencies (see above) before build.**
+
Solidity project uses CMake to configure the build.
Building Solidity is quite similar on Linux, macOS and other Unices:
diff --git a/docs/solidity-by-example.rst b/docs/solidity-by-example.rst
index 139c8a42..59ab7962 100644
--- a/docs/solidity-by-example.rst
+++ b/docs/solidity-by-example.rst
@@ -221,8 +221,7 @@ activate themselves.
// absolute unix timestamps (seconds since 1970-01-01)
// or time periods in seconds.
address public beneficiary;
- uint public auctionStart;
- uint public biddingTime;
+ uint public auctionEnd;
// Current state of the auction.
address public highestBidder;
@@ -251,8 +250,7 @@ activate themselves.
address _beneficiary
) {
beneficiary = _beneficiary;
- auctionStart = now;
- biddingTime = _biddingTime;
+ auctionEnd = now + _biddingTime;
}
/// Bid on the auction with the value sent
@@ -268,7 +266,7 @@ activate themselves.
// Revert the call if the bidding
// period is over.
- require(now <= (auctionStart + biddingTime));
+ require(now <= auctionEnd);
// If the bid is not higher, send the
// money back.
@@ -322,7 +320,7 @@ activate themselves.
// external contracts.
// 1. Conditions
- require(now >= (auctionStart + biddingTime)); // auction did not yet end
+ require(now >= auctionEnd); // auction did not yet end
require(!ended); // this function has already been called
// 2. Effects
@@ -382,7 +380,6 @@ high or low invalid bids.
}
address public beneficiary;
- uint public auctionStart;
uint public biddingEnd;
uint public revealEnd;
bool public ended;
@@ -410,7 +407,6 @@ high or low invalid bids.
address _beneficiary
) {
beneficiary = _beneficiary;
- auctionStart = now;
biddingEnd = now + _biddingTime;
revealEnd = biddingEnd + _revealTime;
}
diff --git a/libdevcore/CommonIO.cpp b/libdevcore/CommonIO.cpp
index 5d47937b..8c7e08f6 100644
--- a/libdevcore/CommonIO.cpp
+++ b/libdevcore/CommonIO.cpp
@@ -39,7 +39,7 @@ namespace
{
template <typename _T>
-inline _T contentsGeneric(std::string const& _file)
+inline _T readFile(std::string const& _file)
{
_T ret;
size_t const c_elementSize = sizeof(typename _T::value_type);
@@ -61,9 +61,23 @@ inline _T contentsGeneric(std::string const& _file)
}
-string dev::contentsString(string const& _file)
+string dev::readFileAsString(string const& _file)
{
- return contentsGeneric<string>(_file);
+ return readFile<string>(_file);
+}
+
+string dev::readStandardInput()
+{
+ string ret;
+ while (!cin.eof())
+ {
+ string tmp;
+ // NOTE: this will read until EOF or NL
+ getline(cin, tmp);
+ ret.append(tmp);
+ ret.append("\n");
+ }
+ return ret;
}
void dev::writeFile(std::string const& _file, bytesConstRef _data, bool _writeDeleteRename)
diff --git a/libdevcore/CommonIO.h b/libdevcore/CommonIO.h
index d84362cf..33769ec3 100644
--- a/libdevcore/CommonIO.h
+++ b/libdevcore/CommonIO.h
@@ -32,7 +32,10 @@ namespace dev
/// Retrieve and returns the contents of the given file as a std::string.
/// If the file doesn't exist or isn't readable, returns an empty container / bytes.
-std::string contentsString(std::string const& _file);
+std::string readFileAsString(std::string const& _file);
+
+/// Retrieve and returns the contents of standard input (until EOF).
+std::string readStandardInput();
/// Write the given binary data into the given file, replacing the file if it pre-exists.
/// Throws exception on error.
diff --git a/liblll/CodeFragment.cpp b/liblll/CodeFragment.cpp
index d4ef3888..5c68194b 100644
--- a/liblll/CodeFragment.cpp
+++ b/liblll/CodeFragment.cpp
@@ -47,6 +47,32 @@ void CodeFragment::finalise(CompilerState const& _cs)
}
}
+namespace
+{
+/// Returns true iff the instruction is valid in "inline assembly".
+bool validAssemblyInstruction(string us)
+{
+ auto it = c_instructions.find(us);
+ return !(
+ it == c_instructions.end() ||
+ solidity::isPushInstruction(it->second)
+ );
+}
+
+/// Returns true iff the instruction is valid as a function.
+bool validFunctionalInstruction(string us)
+{
+ auto it = c_instructions.find(us);
+ return !(
+ it == c_instructions.end() ||
+ solidity::isPushInstruction(it->second) ||
+ solidity::isDupInstruction(it->second) ||
+ solidity::isSwapInstruction(it->second) ||
+ it->second == solidity::Instruction::JUMPDEST
+ );
+}
+}
+
CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback const& _readFile, bool _allowASM):
m_readFile(_readFile)
{
@@ -80,7 +106,7 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback
auto sr = _t.get<sp::basic_string<boost::iterator_range<char const*>, sp::utree_type::symbol_type>>();
string s(sr.begin(), sr.end());
string us = boost::algorithm::to_upper_copy(s);
- if (_allowASM && c_instructions.count(us))
+ if (_allowASM && c_instructions.count(us) && validAssemblyInstruction(us))
m_asm.append(c_instructions.at(us));
else if (_s.defs.count(s))
m_asm.append(_s.defs.at(s).m_asm);
@@ -114,22 +140,6 @@ CodeFragment::CodeFragment(sp::utree const& _t, CompilerState& _s, ReadCallback
}
}
-namespace
-{
-/// Returns true iff the instruction is valid as a function.
-bool validFunctionalInstruction(string us)
-{
- auto it = c_instructions.find(us);
- return !(
- it == c_instructions.end() ||
- solidity::isPushInstruction(it->second) ||
- solidity::isDupInstruction(it->second) ||
- solidity::isSwapInstruction(it->second) ||
- it->second == solidity::Instruction::JUMPDEST
- );
-}
-}
-
void CodeFragment::constructOperation(sp::utree const& _t, CompilerState& _s)
{
if (_t.tag() == 0 && _t.empty())
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index 6636ad97..bc3b7cf1 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -28,6 +28,7 @@ using namespace std;
using namespace dev;
using namespace dev::solidity;
+/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
{
TypePointer const& subType = _operation.subExpression().annotation().type;
@@ -37,6 +38,7 @@ void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
_operation.annotation().type = t;
}
+/// FIXME: this is pretty much a copy of TypeChecker::endVisit(BinaryOperation)
void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
{
TypePointer const& leftType = _operation.leftExpression().annotation().type;
@@ -46,9 +48,24 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
if (!dynamic_cast<RationalNumberType const*>(rightType.get()))
m_errorReporter.fatalTypeError(_operation.rightExpression().location(), "Invalid constant expression.");
TypePointer commonType = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
- if (Token::isCompareOp(_operation.getOperator()))
- commonType = make_shared<BoolType>();
- _operation.annotation().type = commonType;
+ if (!commonType)
+ {
+ m_errorReporter.typeError(
+ _operation.location(),
+ "Operator " +
+ string(Token::toString(_operation.getOperator())) +
+ " not compatible with types " +
+ leftType->toString() +
+ " and " +
+ rightType->toString()
+ );
+ commonType = leftType;
+ }
+ _operation.annotation().commonType = commonType;
+ _operation.annotation().type =
+ Token::isCompareOp(_operation.getOperator()) ?
+ make_shared<BoolType>() :
+ commonType;
}
void ConstantEvaluator::endVisit(Literal const& _literal)
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index ffa538b6..bd8ee597 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -150,10 +150,18 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
if (_memberAccess.memberName() == "callcode")
if (auto const* type = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
if (type->kind() == FunctionType::Kind::BareCallCode)
- m_errorReporter.warning(
- _memberAccess.location(),
- "\"callcode\" has been deprecated in favour of \"delegatecall\"."
- );
+ {
+ if (m_currentContract->sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::V050))
+ m_errorReporter.typeError(
+ _memberAccess.location(),
+ "\"callcode\" has been deprecated in favour of \"delegatecall\"."
+ );
+ else
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "\"callcode\" has been deprecated in favour of \"delegatecall\"."
+ );
+ }
if (m_constructor && m_currentContract)
if (ContractType const* type = dynamic_cast<ContractType const*>(_memberAccess.expression().annotation().type.get()))
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index c2fba565..746e762e 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -1293,6 +1293,12 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
components[i]->accept(*this);
types.push_back(type(*components[i]));
+
+ // Note: code generation will visit each of the expression even if they are not assigned from.
+ if (types[i]->category() == Type::Category::RationalNumber && components.size() > 1)
+ if (!dynamic_cast<RationalNumberType const&>(*types[i]).mobileType())
+ m_errorReporter.fatalTypeError(components[i]->location(), "Invalid rational number.");
+
if (_tuple.isInlineArray())
solAssert(!!types[i], "Inline array cannot have empty components");
if (_tuple.isInlineArray())
diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h
index 15735368..46675e51 100644
--- a/libsolidity/ast/ASTForward.h
+++ b/libsolidity/ast/ASTForward.h
@@ -57,6 +57,7 @@ class UserDefinedTypeName;
class FunctionTypeName;
class Mapping;
class ArrayTypeName;
+class InlineAssembly;
class Statement;
class Block;
class PlaceholderStatement;
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 429db532..74565ae4 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -251,13 +251,10 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
FunctionDefinition const* fallback = _contract.fallbackFunction();
eth::AssemblyItem notFound = m_context.newTag();
- // shortcut messages without data if we have many functions in order to be able to receive
- // ether with constant gas
- if (interfaceFunctions.size() > 5 || fallback)
- {
- m_context << Instruction::CALLDATASIZE << Instruction::ISZERO;
- m_context.appendConditionalJumpTo(notFound);
- }
+ // directly jump to fallback if the data is too short to contain a function selector
+ // also guards against short data
+ m_context << u256(4) << Instruction::CALLDATASIZE << Instruction::LT;
+ m_context.appendConditionalJumpTo(notFound);
// retrieve the function signature hash from the calldata
if (!interfaceFunctions.empty())
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index 7c8c089e..2d2f05ec 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -494,10 +494,10 @@ void SMTChecker::createVariable(VariableDeclaration const& _varDecl, bool _setTo
{
solAssert(m_currentSequenceCounter.count(&_varDecl) == 0, "");
solAssert(m_nextFreeSequenceCounter.count(&_varDecl) == 0, "");
- solAssert(m_Variables.count(&_varDecl) == 0, "");
+ solAssert(m_variables.count(&_varDecl) == 0, "");
m_currentSequenceCounter[&_varDecl] = 0;
m_nextFreeSequenceCounter[&_varDecl] = 1;
- m_Variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
+ m_variables.emplace(&_varDecl, m_interface->newFunction(uniqueSymbol(_varDecl), smt::Sort::Int, smt::Sort::Int));
setValue(_varDecl, _setToZero);
}
else
@@ -566,7 +566,7 @@ smt::Expression SMTChecker::maxValue(IntegerType const& _t)
smt::Expression SMTChecker::expr(Expression const& _e)
{
- if (!m_Expressions.count(&_e))
+ if (!m_expressions.count(&_e))
{
solAssert(_e.annotation().type, "");
switch (_e.annotation().type->category())
@@ -575,24 +575,24 @@ smt::Expression SMTChecker::expr(Expression const& _e)
{
if (RationalNumberType const* rational = dynamic_cast<RationalNumberType const*>(_e.annotation().type.get()))
solAssert(!rational->isFractional(), "");
- m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
}
case Type::Category::Integer:
- m_Expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newInteger(uniqueSymbol(_e)));
break;
case Type::Category::Bool:
- m_Expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
+ m_expressions.emplace(&_e, m_interface->newBool(uniqueSymbol(_e)));
break;
default:
solAssert(false, "Type not implemented.");
}
}
- return m_Expressions.at(&_e);
+ return m_expressions.at(&_e);
}
smt::Expression SMTChecker::var(Declaration const& _decl)
{
- solAssert(m_Variables.count(&_decl), "");
- return m_Variables.at(&_decl);
+ solAssert(m_variables.count(&_decl), "");
+ return m_variables.at(&_decl);
}
diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h
index d23fd201..faaac639 100644
--- a/libsolidity/formal/SMTChecker.h
+++ b/libsolidity/formal/SMTChecker.h
@@ -103,8 +103,8 @@ private:
std::shared_ptr<smt::SolverInterface> m_interface;
std::map<Declaration const*, int> m_currentSequenceCounter;
std::map<Declaration const*, int> m_nextFreeSequenceCounter;
- std::map<Expression const*, smt::Expression> m_Expressions;
- std::map<Declaration const*, smt::Expression> m_Variables;
+ std::map<Expression const*, smt::Expression> m_expressions;
+ std::map<Declaration const*, smt::Expression> m_variables;
ErrorReporter& m_errorReporter;
FunctionDefinition const* m_currentFunction = nullptr;
diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp
index cbd766fb..c627057a 100644
--- a/libsolidity/formal/SMTLib2Interface.cpp
+++ b/libsolidity/formal/SMTLib2Interface.cpp
@@ -64,6 +64,8 @@ void SMTLib2Interface::pop()
Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codomain)
{
+ solAssert(!m_variables.count(_name), "");
+ m_variables[_name] = SMTVariableType::Function;
write(
"(declare-fun |" +
_name +
@@ -78,12 +80,16 @@ Expression SMTLib2Interface::newFunction(string _name, Sort _domain, Sort _codom
Expression SMTLib2Interface::newInteger(string _name)
{
+ solAssert(!m_variables.count(_name), "");
+ m_variables[_name] = SMTVariableType::Integer;
write("(declare-const |" + _name + "| Int)");
return SolverInterface::newInteger(move(_name));
}
Expression SMTLib2Interface::newBool(string _name)
{
+ solAssert(!m_variables.count(_name), "");
+ m_variables[_name] = SMTVariableType::Bool;
write("(declare-const |" + _name + "| Bool)");
return SolverInterface::newBool(std::move(_name));
}
@@ -145,7 +151,8 @@ string SMTLib2Interface::checkSatAndGetValuesCommand(vector<Expression> const& _
for (size_t i = 0; i < _expressionsToEvaluate.size(); i++)
{
auto const& e = _expressionsToEvaluate.at(i);
- // TODO they don't have to be ints...
+ solAssert(m_variables.count(e.name), "");
+ solAssert(m_variables[e.name] == SMTVariableType::Integer, "");
command += "(declare-const |EVALEXPR_" + to_string(i) + "| Int)\n";
command += "(assert (= |EVALEXPR_" + to_string(i) + "| " + toSExpr(e) + "))\n";
}
diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h
index 63188acd..e827449f 100644
--- a/libsolidity/formal/SMTLib2Interface.h
+++ b/libsolidity/formal/SMTLib2Interface.h
@@ -68,6 +68,14 @@ private:
ReadCallback::Callback m_queryCallback;
std::vector<std::string> m_accumulatedOutput;
+
+ enum class SMTVariableType {
+ Function,
+ Integer,
+ Bool
+ };
+
+ std::map<std::string,SMTVariableType> m_variables;
};
}
diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp
index 0ceed3a7..6111b2c8 100644
--- a/libsolidity/formal/Z3Interface.cpp
+++ b/libsolidity/formal/Z3Interface.cpp
@@ -73,28 +73,37 @@ void Z3Interface::addAssertion(Expression const& _expr)
pair<CheckResult, vector<string>> Z3Interface::check(vector<Expression> const& _expressionsToEvaluate)
{
CheckResult result;
- switch (m_solver.check())
+ vector<string> values;
+ try
{
- case z3::check_result::sat:
- result = CheckResult::SATISFIABLE;
- break;
- case z3::check_result::unsat:
- result = CheckResult::UNSATISFIABLE;
- break;
- case z3::check_result::unknown:
- result = CheckResult::UNKNOWN;
- break;
- default:
- solAssert(false, "");
+ switch (m_solver.check())
+ {
+ case z3::check_result::sat:
+ result = CheckResult::SATISFIABLE;
+ break;
+ case z3::check_result::unsat:
+ result = CheckResult::UNSATISFIABLE;
+ break;
+ case z3::check_result::unknown:
+ result = CheckResult::UNKNOWN;
+ break;
+ default:
+ solAssert(false, "");
+ }
+
+ if (result != CheckResult::UNSATISFIABLE)
+ {
+ z3::model m = m_solver.get_model();
+ for (Expression const& e: _expressionsToEvaluate)
+ values.push_back(toString(m.eval(toZ3Expr(e))));
+ }
}
-
- vector<string> values;
- if (result != CheckResult::UNSATISFIABLE)
+ catch (z3::exception const&)
{
- z3::model m = m_solver.get_model();
- for (Expression const& e: _expressionsToEvaluate)
- values.push_back(toString(m.eval(toZ3Expr(e))));
+ result = CheckResult::ERROR;
+ values.clear();
}
+
return make_pair(result, values);
}
@@ -118,8 +127,7 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
{">=", 2},
{"+", 2},
{"-", 2},
- {"*", 2},
- {">=", 2}
+ {"*", 2}
};
string const& n = _expr.name;
if (m_functions.count(n))
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index b99fe4ee..5713256a 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -747,22 +747,32 @@ void CompilerStack::compileContract(
}
}
+string const CompilerStack::lastContractName() const
+{
+ if (m_contracts.empty())
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
+ // try to find some user-supplied contract
+ string contractName;
+ for (auto const& it: m_sources)
+ for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
+ if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
+ contractName = contract->fullyQualifiedName();
+ return contractName;
+}
+
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
{
if (m_contracts.empty())
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
- string contractName = _contractName;
- if (_contractName.empty())
- // try to find some user-supplied contract
- for (auto const& it: m_sources)
- for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
- if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
- contractName = contract->fullyQualifiedName();
- auto it = m_contracts.find(contractName);
+
+ auto it = m_contracts.find(_contractName);
+ if (it != m_contracts.end())
+ return it->second;
+
// To provide a measure of backward-compatibility, if a contract is not located by its
// fully-qualified name, a lookup will be attempted purely on the contract's name to see
// if anything will satisfy.
- if (it == m_contracts.end() && contractName.find(":") == string::npos)
+ if (_contractName.find(":") == string::npos)
{
for (auto const& contractEntry: m_contracts)
{
@@ -773,12 +783,13 @@ CompilerStack::Contract const& CompilerStack::contract(string const& _contractNa
string foundName;
getline(ss, source, ':');
getline(ss, foundName, ':');
- if (foundName == contractName) return contractEntry.second;
+ if (foundName == _contractName)
+ return contractEntry.second;
}
- // If we get here, both lookup methods failed.
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract " + _contractName + " not found."));
}
- return it->second;
+
+ // If we get here, both lookup methods failed.
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Contract \"" + _contractName + "\" not found."));
}
CompilerStack::Source const& CompilerStack::source(string const& _sourceName) const
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index c567ac2c..b377b3aa 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -155,10 +155,10 @@ public:
std::map<std::string, unsigned> sourceIndices() const;
/// @returns the previously used scanner, useful for counting lines during error reporting.
- Scanner const& scanner(std::string const& _sourceName = "") const;
+ 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;
+ SourceUnit const& ast(std::string const& _sourceName) 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:
@@ -168,48 +168,51 @@ public:
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
+ /// @returns the name of the last contract.
+ std::string const lastContractName() const;
+
/// @returns either the contract's name or a mixture of its name and source file, sanitized for filesystem use
std::string const filesystemFriendlyName(std::string const& _contractName) const;
/// @returns the assembled object for a contract.
- eth::LinkerObject const& object(std::string const& _contractName = "") const;
+ eth::LinkerObject const& object(std::string const& _contractName) const;
/// @returns the runtime object for the contract.
- eth::LinkerObject const& runtimeObject(std::string const& _contractName = "") const;
+ eth::LinkerObject const& runtimeObject(std::string const& _contractName) const;
/// @returns the bytecode of a contract that uses an already deployed contract via DELEGATECALL.
/// The returned bytes will contain a sequence of 20 bytes of the format "XXX...XXX" which have to
/// substituted by the actual address. Note that this sequence starts end ends in three X
/// characters but can contain anything in between.
- eth::LinkerObject const& cloneObject(std::string const& _contractName = "") const;
+ eth::LinkerObject const& cloneObject(std::string const& _contractName) const;
/// @returns normal contract assembly items
- eth::AssemblyItems const* assemblyItems(std::string const& _contractName = "") const;
+ eth::AssemblyItems const* assemblyItems(std::string const& _contractName) const;
/// @returns runtime contract assembly items
- eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName = "") const;
+ eth::AssemblyItems const* runtimeAssemblyItems(std::string const& _contractName) const;
/// @returns the string that provides a mapping between bytecode and sourcecode or a nullptr
/// if the contract does not (yet) have bytecode.
- std::string const* sourceMapping(std::string const& _contractName = "") const;
+ std::string const* sourceMapping(std::string const& _contractName) const;
/// @returns the string that provides a mapping between runtime bytecode and sourcecode.
/// if the contract does not (yet) have bytecode.
- std::string const* runtimeSourceMapping(std::string const& _contractName = "") const;
+ std::string const* runtimeSourceMapping(std::string const& _contractName) const;
/// @return a verbose text representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
- std::string assemblyString(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
+ std::string assemblyString(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representation of the assembly.
/// @arg _sourceCodes is the map of input files to source code strings
/// Prerequisite: Successful compilation.
- Json::Value assemblyJSON(std::string const& _contractName = "", StringMap _sourceCodes = StringMap()) const;
+ Json::Value assemblyJSON(std::string const& _contractName, StringMap _sourceCodes = StringMap()) const;
/// @returns a JSON representing the contract ABI.
/// Prerequisite: Successful call to parse or compile.
- Json::Value const& contractABI(std::string const& _contractName = "") const;
+ Json::Value const& contractABI(std::string const& _contractName) const;
/// @returns a JSON representing the contract's user documentation.
/// Prerequisite: Successful call to parse or compile.
@@ -276,8 +279,8 @@ private:
);
void link();
- Contract const& contract(std::string const& _contractName = "") const;
- Source const& source(std::string const& _sourceName = "") const;
+ 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.
diff --git a/lllc/main.cpp b/lllc/main.cpp
index 912ce16a..5679bc2b 100644
--- a/lllc/main.cpp
+++ b/lllc/main.cpp
@@ -35,15 +35,15 @@ using namespace dev::solidity;
using namespace dev::eth;
static string const VersionString =
- string(ETH_PROJECT_VERSION) +
- (string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
- (string(SOL_VERSION_BUILDINFO).empty() ? "" : "+" + string(SOL_VERSION_BUILDINFO));
+ string(ETH_PROJECT_VERSION) +
+ (string(SOL_VERSION_PRERELEASE).empty() ? "" : "-" + string(SOL_VERSION_PRERELEASE)) +
+ (string(SOL_VERSION_BUILDINFO).empty() ? "" : "+" + string(SOL_VERSION_BUILDINFO));
static void help()
{
cout
<< "Usage lllc [OPTIONS] <file>" << endl
- << "Options:" << endl
+ << "Options:" << endl
<< " -b,--binary Parse, compile and assemble; output byte code in binary." << endl
<< " -x,--hex Parse, compile and assemble; output byte code in hex." << endl
<< " -a,--assembly Only parse and compile; show assembly." << endl
@@ -51,12 +51,12 @@ static void help()
<< " -o,--optimise Turn on/off the optimiser; off by default." << endl
<< " -h,--help Show this help message and exit." << endl
<< " -V,--version Show the version and exit." << endl;
- exit(0);
+ exit(0);
}
static void version()
{
- cout << "LLLC, the Lovely Little Language Compiler " << endl;
+ cout << "LLLC, the Lovely Little Language Compiler" << endl;
cout << "Version: " << VersionString << endl;
exit(0);
}
@@ -118,39 +118,39 @@ int main(int argc, char** argv)
string src;
if (infile.empty())
- {
- string s;
- while (!cin.eof())
- {
- getline(cin, s);
- src.append(s);
- }
- }
+ src = readStandardInput();
else
- src = contentsString(infile);
+ src = readFileAsString(infile);
vector<string> errors;
if (src.empty())
+ {
errors.push_back("Empty file.");
+ }
else if (mode == Disassemble)
{
cout << disassemble(fromHex(src)) << endl;
}
else if (mode == Binary || mode == Hex)
{
- auto bs = compileLLL(src, optimise ? true : false, &errors, contentsString);
+ auto bs = compileLLL(src, optimise ? true : false, &errors, readFileAsString);
if (mode == Hex)
cout << toHex(bs) << endl;
else if (mode == Binary)
cout.write((char const*)bs.data(), bs.size());
}
else if (mode == ParseTree)
+ {
cout << parseLLL(src) << endl;
+ }
else if (mode == Assembly)
- cout << compileLLLToAsm(src, optimise ? true : false, &errors, contentsString) << endl;
+ {
+ cout << compileLLLToAsm(src, optimise ? true : false, &errors, readFileAsString) << endl;
+ }
+
for (auto const& i: errors)
cerr << i << endl;
- if ( errors.size() )
+ if (errors.size())
return 1;
return 0;
}
diff --git a/scripts/test_emscripten.sh b/scripts/test_emscripten.sh
index b01b33bb..4996e957 100755
--- a/scripts/test_emscripten.sh
+++ b/scripts/test_emscripten.sh
@@ -36,6 +36,10 @@ DIR=$(mktemp -d)
echo "Preparing solc-js..."
git clone --depth 1 https://github.com/ethereum/solc-js "$DIR"
cd "$DIR"
+ # disable "prepublish" script which downloads the latest version
+ # (we will replace it anyway and it is often incorrectly cached
+ # on travis)
+ npm config set script.prepublish ''
npm install
# Replace soljson with current build
diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp
index 1686dc2e..9e2cb77a 100644
--- a/solc/CommandLineInterface.cpp
+++ b/solc/CommandLineInterface.cpp
@@ -424,20 +424,13 @@ void CommandLineInterface::readInputFilesAndConfigureRemappings()
continue;
}
- m_sourceCodes[infile.string()] = dev::contentsString(infile.string());
+ m_sourceCodes[infile.string()] = dev::readFileAsString(infile.string());
path = boost::filesystem::canonical(infile).string();
}
m_allowedDirectories.push_back(boost::filesystem::path(path).remove_filename());
}
if (addStdin)
- {
- string s;
- while (!cin.eof())
- {
- getline(cin, s);
- m_sourceCodes[g_stdinFileName].append(s + '\n');
- }
- }
+ m_sourceCodes[g_stdinFileName] = dev::readStandardInput();
}
bool CommandLineInterface::parseLibraryOption(string const& _input)
@@ -447,7 +440,7 @@ bool CommandLineInterface::parseLibraryOption(string const& _input)
try
{
if (fs::is_regular_file(_input))
- data = contentsString(_input);
+ data = readFileAsString(_input);
}
catch (fs::filesystem_error const&)
{
@@ -698,7 +691,7 @@ bool CommandLineInterface::processInput()
return ReadCallback::Result{false, "Not a valid file."};
else
{
- auto contents = dev::contentsString(canonicalPath.string());
+ auto contents = dev::readFileAsString(canonicalPath.string());
m_sourceCodes[path.string()] = contents;
return ReadCallback::Result{true, contents};
}
@@ -731,13 +724,7 @@ bool CommandLineInterface::processInput()
if (m_args.count(g_argStandardJSON))
{
- string input;
- while (!cin.eof())
- {
- string tmp;
- getline(cin, tmp);
- input.append(tmp + "\n");
- }
+ string input = dev::readStandardInput();
StandardCompiler compiler(fileReader);
cout << compiler.compile(input) << endl;
return true;
@@ -951,9 +938,10 @@ void CommandLineInterface::handleAst(string const& _argStr)
for (auto const& sourceCode: m_sourceCodes)
asts.push_back(&m_compiler->ast(sourceCode.first));
map<ASTNode const*, eth::GasMeter::GasConsumption> gasCosts;
- if (m_compiler->runtimeAssemblyItems())
+ // FIXME: shouldn't this be done for every contract?
+ if (m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()))
gasCosts = GasEstimator::breakToStatementLevel(
- GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(), asts),
+ GasEstimator::structuralEstimation(*m_compiler->runtimeAssemblyItems(m_compiler->lastContractName()), asts),
asts
);
diff --git a/test/ExecutionFramework.h b/test/ExecutionFramework.h
index cc25bea7..2c61c0a6 100644
--- a/test/ExecutionFramework.h
+++ b/test/ExecutionFramework.h
@@ -172,78 +172,13 @@ public:
{
return bytes();
}
+
//@todo might be extended in the future
template <class Arg>
static bytes encodeDyn(Arg const& _arg)
{
return encodeArgs(u256(0x20), u256(_arg.size()), _arg);
}
- class ContractInterface
- {
- public:
- ContractInterface(ExecutionFramework& _framework): m_framework(_framework) {}
-
- void setNextValue(u256 const& _value) { m_nextValue = _value; }
-
- protected:
- template <class... Args>
- bytes const& call(std::string const& _sig, Args const&... _arguments)
- {
- auto const& ret = m_framework.callContractFunctionWithValue(_sig, m_nextValue, _arguments...);
- m_nextValue = 0;
- return ret;
- }
-
- void callString(std::string const& _name, std::string const& _arg)
- {
- BOOST_CHECK(call(_name + "(string)", u256(0x20), _arg.length(), _arg).empty());
- }
-
- void callStringAddress(std::string const& _name, std::string const& _arg1, u160 const& _arg2)
- {
- BOOST_CHECK(call(_name + "(string,address)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
- }
-
- void callStringAddressBool(std::string const& _name, std::string const& _arg1, u160 const& _arg2, bool _arg3)
- {
- BOOST_CHECK(call(_name + "(string,address,bool)", u256(0x60), _arg2, _arg3, _arg1.length(), _arg1).empty());
- }
-
- void callStringBytes32(std::string const& _name, std::string const& _arg1, h256 const& _arg2)
- {
- BOOST_CHECK(call(_name + "(string,bytes32)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
- }
-
- u160 callStringReturnsAddress(std::string const& _name, std::string const& _arg)
- {
- bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
- BOOST_REQUIRE(ret.size() == 0x20);
- BOOST_CHECK(std::count(ret.begin(), ret.begin() + 12, 0) == 12);
- return u160(u256(h256(ret)));
- }
-
- std::string callAddressReturnsString(std::string const& _name, u160 const& _arg)
- {
- bytesConstRef const ret(&call(_name + "(address)", _arg));
- BOOST_REQUIRE(ret.size() >= 0x40);
- u256 offset(h256(ret.cropped(0, 0x20)));
- BOOST_REQUIRE_EQUAL(offset, 0x20);
- u256 len(h256(ret.cropped(0x20, 0x20)));
- BOOST_REQUIRE_EQUAL(ret.size(), 0x40 + ((len + 0x1f) / 0x20) * 0x20);
- return ret.cropped(0x40, size_t(len)).toString();
- }
-
- h256 callStringReturnsBytes32(std::string const& _name, std::string const& _arg)
- {
- bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
- BOOST_REQUIRE(ret.size() == 0x20);
- return h256(ret);
- }
-
- private:
- u256 m_nextValue;
- ExecutionFramework& m_framework;
- };
private:
template <class CppFunction, class... Args>
diff --git a/test/RPCSession.cpp b/test/RPCSession.cpp
index 72b26453..c06c3997 100644
--- a/test/RPCSession.cpp
+++ b/test/RPCSession.cpp
@@ -74,7 +74,10 @@ IPCSocket::IPCSocket(string const& _path): m_path(_path)
BOOST_FAIL("Error creating IPC socket object");
if (connect(m_socket, reinterpret_cast<struct sockaddr const*>(&saun), sizeof(struct sockaddr_un)) < 0)
+ {
+ close(m_socket);
BOOST_FAIL("Error connecting to IPC socket: " << _path);
+ }
#endif
}
@@ -336,22 +339,25 @@ Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const&
return result["result"];
}
+string const& RPCSession::accountCreate()
+{
+ m_accounts.push_back(personal_newAccount(""));
+ personal_unlockAccount(m_accounts.back(), "", 100000);
+ return m_accounts.back();
+}
+
string const& RPCSession::accountCreateIfNotExists(size_t _id)
{
- if (_id >= m_accounts.size())
- {
- m_accounts.push_back(personal_newAccount(""));
- personal_unlockAccount(m_accounts.back(), "", 100000);
- }
+ while ((_id + 1) > m_accounts.size())
+ accountCreate();
return m_accounts[_id];
}
RPCSession::RPCSession(const string& _path):
m_ipcSocket(_path)
{
- string account = personal_newAccount("");
- personal_unlockAccount(account, "", 100000);
- m_accounts.push_back(account);
+ accountCreate();
+ // This will pre-fund the accounts create prior.
test_setChainParams(m_accounts);
}
diff --git a/test/RPCSession.h b/test/RPCSession.h
index eae6a09c..63f1dd21 100644
--- a/test/RPCSession.h
+++ b/test/RPCSession.h
@@ -121,6 +121,7 @@ public:
Json::Value rpcCall(std::string const& _methodName, std::vector<std::string> const& _args = std::vector<std::string>(), bool _canFail = false);
std::string const& account(size_t _id) const { return m_accounts.at(_id); }
+ std::string const& accountCreate();
std::string const& accountCreateIfNotExists(size_t _id);
private:
diff --git a/test/contracts/AuctionRegistrar.cpp b/test/contracts/AuctionRegistrar.cpp
index 73a5d1ed..c9c744af 100644
--- a/test/contracts/AuctionRegistrar.cpp
+++ b/test/contracts/AuctionRegistrar.cpp
@@ -24,6 +24,7 @@
#include <tuple>
#include <boost/test/unit_test.hpp>
#include <test/libsolidity/SolidityExecutionFramework.h>
+#include <test/contracts/ContractInterface.h>
using namespace std;
using namespace dev::test;
@@ -230,7 +231,6 @@ protected:
BOOST_REQUIRE(!m_output.empty());
}
- using ContractInterface = SolidityExecutionFramework::ContractInterface;
class RegistrarInterface: public ContractInterface
{
public:
diff --git a/test/contracts/ContractInterface.h b/test/contracts/ContractInterface.h
new file mode 100644
index 00000000..052b0db2
--- /dev/null
+++ b/test/contracts/ContractInterface.h
@@ -0,0 +1,99 @@
+/*
+ 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/>.
+*/
+
+#pragma once
+
+#include <boost/test/unit_test.hpp>
+#include <test/ExecutionFramework.h>
+
+#include <functional>
+
+namespace dev
+{
+namespace test
+{
+
+class ContractInterface
+{
+public:
+ ContractInterface(ExecutionFramework& _framework): m_framework(_framework) {}
+
+ void setNextValue(u256 const& _value) { m_nextValue = _value; }
+
+protected:
+ template <class... Args>
+ bytes const& call(std::string const& _sig, Args const&... _arguments)
+ {
+ auto const& ret = m_framework.callContractFunctionWithValue(_sig, m_nextValue, _arguments...);
+ m_nextValue = 0;
+ return ret;
+ }
+
+ void callString(std::string const& _name, std::string const& _arg)
+ {
+ BOOST_CHECK(call(_name + "(string)", u256(0x20), _arg.length(), _arg).empty());
+ }
+
+ void callStringAddress(std::string const& _name, std::string const& _arg1, u160 const& _arg2)
+ {
+ BOOST_CHECK(call(_name + "(string,address)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
+ }
+
+ void callStringAddressBool(std::string const& _name, std::string const& _arg1, u160 const& _arg2, bool _arg3)
+ {
+ BOOST_CHECK(call(_name + "(string,address,bool)", u256(0x60), _arg2, _arg3, _arg1.length(), _arg1).empty());
+ }
+
+ void callStringBytes32(std::string const& _name, std::string const& _arg1, h256 const& _arg2)
+ {
+ BOOST_CHECK(call(_name + "(string,bytes32)", u256(0x40), _arg2, _arg1.length(), _arg1).empty());
+ }
+
+ u160 callStringReturnsAddress(std::string const& _name, std::string const& _arg)
+ {
+ bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
+ BOOST_REQUIRE(ret.size() == 0x20);
+ BOOST_CHECK(std::count(ret.begin(), ret.begin() + 12, 0) == 12);
+ return u160(u256(h256(ret)));
+ }
+
+ std::string callAddressReturnsString(std::string const& _name, u160 const& _arg)
+ {
+ bytesConstRef const ret(&call(_name + "(address)", _arg));
+ BOOST_REQUIRE(ret.size() >= 0x40);
+ u256 offset(h256(ret.cropped(0, 0x20)));
+ BOOST_REQUIRE_EQUAL(offset, 0x20);
+ u256 len(h256(ret.cropped(0x20, 0x20)));
+ BOOST_REQUIRE_EQUAL(ret.size(), 0x40 + ((len + 0x1f) / 0x20) * 0x20);
+ return ret.cropped(0x40, size_t(len)).toString();
+ }
+
+ h256 callStringReturnsBytes32(std::string const& _name, std::string const& _arg)
+ {
+ bytes const& ret = call(_name + "(string)", u256(0x20), _arg.length(), _arg);
+ BOOST_REQUIRE(ret.size() == 0x20);
+ return h256(ret);
+ }
+
+private:
+ u256 m_nextValue;
+ ExecutionFramework& m_framework;
+};
+
+}
+} // end namespaces
+
diff --git a/test/liblll/Compiler.cpp b/test/liblll/Compiler.cpp
index 2d66bce1..ace97e15 100644
--- a/test/liblll/Compiler.cpp
+++ b/test/liblll/Compiler.cpp
@@ -24,6 +24,7 @@
#include <memory>
#include <boost/test/unit_test.hpp>
#include <liblll/Compiler.h>
+#include <libdevcore/FixedHash.h>
using namespace std;
@@ -37,9 +38,9 @@ namespace test
namespace
{
-bool successCompile(std::string const& _sourceCode)
+bool successCompile(string const& _sourceCode)
{
- std::vector<std::string> errors;
+ vector<string> errors;
bytes bytecode = eth::compileLLL(_sourceCode, false, &errors);
if (!errors.empty())
return false;
@@ -121,6 +122,533 @@ BOOST_AUTO_TEST_CASE(switch_inconsistent_return_count)
BOOST_CHECK(!successCompile(sourceCode));
}
+BOOST_AUTO_TEST_CASE(disallowed_asm_instructions)
+{
+ for (unsigned i = 1; i <= 32; i++)
+ BOOST_CHECK(!successCompile("(asm PUSH" + boost::lexical_cast<string>(i) + ")"));
+}
+
+BOOST_AUTO_TEST_CASE(disallowed_functional_asm_instructions)
+{
+ for (unsigned i = 1; i <= 32; i++)
+ BOOST_CHECK(!successCompile("(PUSH" + boost::lexical_cast<string>(i) + ")"));
+ for (unsigned i = 1; i <= 16; i++)
+ BOOST_CHECK(!successCompile("(DUP" + boost::lexical_cast<string>(i) + ")"));
+ for (unsigned i = 1; i <= 16; i++)
+ BOOST_CHECK(!successCompile("(SWAP" + boost::lexical_cast<string>(i) + ")"));
+ BOOST_CHECK(!successCompile("(JUMPDEST)"));
+}
+
+BOOST_AUTO_TEST_CASE(valid_opcodes_functional)
+{
+ vector<string> opcodes_bytecode {
+ "00",
+ "6000600001",
+ "6000600002",
+ "6000600003",
+ "6000600004",
+ "6000600005",
+ "6000600006",
+ "6000600007",
+ "60006000600008",
+ "60006000600009",
+ "600060000a",
+ "600060000b",
+ "6000600010",
+ "6000600011",
+ "6000600012",
+ "6000600013",
+ "6000600014",
+ "600015",
+ "6000600016",
+ "6000600017",
+ "6000600018",
+ "600019",
+ "600060001a",
+ "6000600020",
+ "30",
+ "600031",
+ "32",
+ "33",
+ "34",
+ "600035",
+ "36",
+ "60006000600037",
+ "38",
+ "60006000600039",
+ "3a",
+ "60003b",
+ "60006000600060003c",
+ "3d",
+ "6000600060003e",
+ "600040",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "600050",
+ "600051",
+ "6000600052",
+ "6000600053",
+ "600054",
+ "6000600055",
+ "600056",
+ "6000600057",
+ "58",
+ "59",
+ "5a",
+ "60ff",
+ "61ffff",
+ "62ffffff",
+ "63ffffffff",
+ "64ffffffffff",
+ "65ffffffffffff",
+ "66ffffffffffffff",
+ "67ffffffffffffffff",
+ "68ffffffffffffffffff",
+ "69ffffffffffffffffffff",
+ "6affffffffffffffffffffff",
+ "6bffffffffffffffffffffffff",
+ "6cffffffffffffffffffffffffff",
+ "6dffffffffffffffffffffffffffff",
+ "6effffffffffffffffffffffffffffff",
+ "6fffffffffffffffffffffffffffffffff",
+ "70ffffffffffffffffffffffffffffffffff",
+ "71ffffffffffffffffffffffffffffffffffff",
+ "72ffffffffffffffffffffffffffffffffffffff",
+ "73ffffffffffffffffffffffffffffffffffffffff",
+ "74ffffffffffffffffffffffffffffffffffffffffff",
+ "75ffffffffffffffffffffffffffffffffffffffffffff",
+ "76ffffffffffffffffffffffffffffffffffffffffffffff",
+ "77ffffffffffffffffffffffffffffffffffffffffffffffff",
+ "78ffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "79ffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7affffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "60006000a0",
+ "600060006000a1",
+ "6000600060006000a2",
+ "60006000600060006000a3",
+ "600060006000600060006000a4",
+ "600060006000f0",
+ "6000600060006000600060006000f1",
+ "6000600060006000600060006000f2",
+ "60006000f3",
+ "600060006000600060006000f4",
+ "600060006000600060006000fa",
+ "60006000fd",
+ "fe",
+ "6000ff"
+ };
+
+ vector<string> opcodes_lll {
+ "{ (STOP) }",
+ "{ (ADD 0 0) }",
+ "{ (MUL 0 0) }",
+ "{ (SUB 0 0) }",
+ "{ (DIV 0 0) }",
+ "{ (SDIV 0 0) }",
+ "{ (MOD 0 0) }",
+ "{ (SMOD 0 0) }",
+ "{ (ADDMOD 0 0 0) }",
+ "{ (MULMOD 0 0 0) }",
+ "{ (EXP 0 0) }",
+ "{ (SIGNEXTEND 0 0) }",
+ "{ (LT 0 0) }",
+ "{ (GT 0 0) }",
+ "{ (SLT 0 0) }",
+ "{ (SGT 0 0) }",
+ "{ (EQ 0 0) }",
+ "{ (ISZERO 0) }",
+ "{ (AND 0 0) }",
+ "{ (OR 0 0) }",
+ "{ (XOR 0 0) }",
+ "{ (NOT 0) }",
+ "{ (BYTE 0 0) }",
+ "{ (KECCAK256 0 0) }",
+ "{ (ADDRESS) }",
+ "{ (BALANCE 0) }",
+ "{ (ORIGIN) }",
+ "{ (CALLER) }",
+ "{ (CALLVALUE) }",
+ "{ (CALLDATALOAD 0) }",
+ "{ (CALLDATASIZE) }",
+ "{ (CALLDATACOPY 0 0 0) }",
+ "{ (CODESIZE) }",
+ "{ (CODECOPY 0 0 0) }",
+ "{ (GASPRICE) }",
+ "{ (EXTCODESIZE 0) }",
+ "{ (EXTCODECOPY 0 0 0 0) }",
+ "{ (RETURNDATASIZE) }",
+ "{ (RETURNDATACOPY 0 0 0) }",
+ "{ (BLOCKHASH 0) }",
+ "{ (COINBASE) }",
+ "{ (TIMESTAMP) }",
+ "{ (NUMBER) }",
+ "{ (DIFFICULTY) }",
+ "{ (GASLIMIT) }",
+ "{ (POP 0) }",
+ "{ (MLOAD 0) }",
+ "{ (MSTORE 0 0) }",
+ "{ (MSTORE8 0 0) }",
+ "{ (SLOAD 0) }",
+ "{ (SSTORE 0 0) }",
+ "{ (JUMP 0) }",
+ "{ (JUMPI 0 0) }",
+ "{ (PC) }",
+ "{ (MSIZE) }",
+ "{ (GAS) }",
+ "{ 0xff }",
+ "{ 0xffff }",
+ "{ 0xffffff }",
+ "{ 0xffffffff }",
+ "{ 0xffffffffff }",
+ "{ 0xffffffffffff }",
+ "{ 0xffffffffffffff }",
+ "{ 0xffffffffffffffff }",
+ "{ 0xffffffffffffffffff }",
+ "{ 0xffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff }",
+ "{ (LOG0 0 0) }",
+ "{ (LOG1 0 0 0) }",
+ "{ (LOG2 0 0 0 0) }",
+ "{ (LOG3 0 0 0 0 0) }",
+ "{ (LOG4 0 0 0 0 0 0) }",
+ "{ (CREATE 0 0 0) }",
+ "{ (CALL 0 0 0 0 0 0 0) }",
+ "{ (CALLCODE 0 0 0 0 0 0 0) }",
+ "{ (RETURN 0 0) }",
+ "{ (DELEGATECALL 0 0 0 0 0 0) }",
+ "{ (STATICCALL 0 0 0 0 0 0) }",
+ "{ (REVERT 0 0) }",
+ "{ (INVALID) }",
+ "{ (SELFDESTRUCT 0) }"
+ };
+
+ for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
+ vector<string> errors;
+ bytes code = eth::compileLLL(opcodes_lll[i], false, &errors);
+
+ BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]);
+
+ BOOST_CHECK_EQUAL(toHex(code), opcodes_bytecode[i]);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(valid_opcodes_asm)
+{
+ vector<string> opcodes_bytecode {
+ "00",
+ "01",
+ "02",
+ "03",
+ "04",
+ "05",
+ "06",
+ "07",
+ "08",
+ "09",
+ "0a",
+ "0b",
+ "10",
+ "11",
+ "12",
+ "13",
+ "14",
+ "15",
+ "16",
+ "17",
+ "18",
+ "19",
+ "1a",
+ "20",
+ "30",
+ "31",
+ "32",
+ "33",
+ "34",
+ "35",
+ "36",
+ "37",
+ "38",
+ "39",
+ "3a",
+ "3b",
+ "3c",
+ "3d",
+ "3e",
+ "40",
+ "41",
+ "42",
+ "43",
+ "44",
+ "45",
+ "50",
+ "51",
+ "52",
+ "53",
+ "54",
+ "55",
+ "56",
+ "57",
+ "58",
+ "59",
+ "5a",
+ "5b",
+ "60ff",
+ "61ffff",
+ "62ffffff",
+ "63ffffffff",
+ "64ffffffffff",
+ "65ffffffffffff",
+ "66ffffffffffffff",
+ "67ffffffffffffffff",
+ "68ffffffffffffffffff",
+ "69ffffffffffffffffffff",
+ "6affffffffffffffffffffff",
+ "6bffffffffffffffffffffffff",
+ "6cffffffffffffffffffffffffff",
+ "6dffffffffffffffffffffffffffff",
+ "6effffffffffffffffffffffffffffff",
+ "6fffffffffffffffffffffffffffffffff",
+ "70ffffffffffffffffffffffffffffffffff",
+ "71ffffffffffffffffffffffffffffffffffff",
+ "72ffffffffffffffffffffffffffffffffffffff",
+ "73ffffffffffffffffffffffffffffffffffffffff",
+ "74ffffffffffffffffffffffffffffffffffffffffff",
+ "75ffffffffffffffffffffffffffffffffffffffffffff",
+ "76ffffffffffffffffffffffffffffffffffffffffffffff",
+ "77ffffffffffffffffffffffffffffffffffffffffffffffff",
+ "78ffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "79ffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7affffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7bffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7cffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "80",
+ "81",
+ "82",
+ "83",
+ "84",
+ "85",
+ "86",
+ "87",
+ "88",
+ "89",
+ "8a",
+ "8b",
+ "8c",
+ "8d",
+ "8e",
+ "8f",
+ "90",
+ "91",
+ "92",
+ "93",
+ "94",
+ "95",
+ "96",
+ "97",
+ "98",
+ "99",
+ "9a",
+ "9b",
+ "9c",
+ "9d",
+ "9e",
+ "9f",
+ "a0",
+ "a1",
+ "a2",
+ "a3",
+ "a4",
+ "f0",
+ "f1",
+ "f2",
+ "f3",
+ "f4",
+ "fa",
+ "fd",
+ "fe",
+ "ff"
+ };
+
+ vector<string> opcodes_lll {
+ "{ (asm STOP) }",
+ "{ (asm ADD) }",
+ "{ (asm MUL) }",
+ "{ (asm SUB) }",
+ "{ (asm DIV) }",
+ "{ (asm SDIV ) }",
+ "{ (asm MOD) }",
+ "{ (asm SMOD) }",
+ "{ (asm ADDMOD) }",
+ "{ (asm MULMOD) }",
+ "{ (asm EXP) }",
+ "{ (asm SIGNEXTEND) }",
+ "{ (asm LT) }",
+ "{ (asm GT) }",
+ "{ (asm SLT) }",
+ "{ (asm SGT) }",
+ "{ (asm EQ) }",
+ "{ (asm ISZERO) }",
+ "{ (asm AND) }",
+ "{ (asm OR) }",
+ "{ (asm XOR) }",
+ "{ (asm NOT) }",
+ "{ (asm BYTE) }",
+ "{ (asm KECCAK256) }",
+ "{ (asm ADDRESS) }",
+ "{ (asm BALANCE) }",
+ "{ (asm ORIGIN) }",
+ "{ (asm CALLER) }",
+ "{ (asm CALLVALUE) }",
+ "{ (asm CALLDATALOAD) }",
+ "{ (asm CALLDATASIZE) }",
+ "{ (asm CALLDATACOPY) }",
+ "{ (asm CODESIZE) }",
+ "{ (asm CODECOPY) }",
+ "{ (asm GASPRICE) }",
+ "{ (asm EXTCODESIZE)}",
+ "{ (asm EXTCODECOPY) }",
+ "{ (asm RETURNDATASIZE) }",
+ "{ (asm RETURNDATACOPY) }",
+ "{ (asm BLOCKHASH) }",
+ "{ (asm COINBASE) }",
+ "{ (asm TIMESTAMP) }",
+ "{ (asm NUMBER) }",
+ "{ (asm DIFFICULTY) }",
+ "{ (asm GASLIMIT) }",
+ "{ (asm POP) }",
+ "{ (asm MLOAD) }",
+ "{ (asm MSTORE) }",
+ "{ (asm MSTORE8) }",
+ "{ (asm SLOAD) }",
+ "{ (asm SSTORE) }",
+ "{ (asm JUMP ) }",
+ "{ (asm JUMPI ) }",
+ "{ (asm PC) }",
+ "{ (asm MSIZE) }",
+ "{ (asm GAS) }",
+ "{ (asm JUMPDEST) }",
+ "{ (asm 0xff) }",
+ "{ (asm 0xffff) }",
+ "{ (asm 0xffffff) }",
+ "{ (asm 0xffffffff) }",
+ "{ (asm 0xffffffffff) }",
+ "{ (asm 0xffffffffffff) }",
+ "{ (asm 0xffffffffffffff) }",
+ "{ (asm 0xffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff) }",
+ "{ (asm DUP1) }",
+ "{ (asm DUP2) }",
+ "{ (asm DUP3) }",
+ "{ (asm DUP4) }",
+ "{ (asm DUP5) }",
+ "{ (asm DUP6) }",
+ "{ (asm DUP7) }",
+ "{ (asm DUP8) }",
+ "{ (asm DUP9) }",
+ "{ (asm DUP10) }",
+ "{ (asm DUP11) }",
+ "{ (asm DUP12) }",
+ "{ (asm DUP13) }",
+ "{ (asm DUP14) }",
+ "{ (asm DUP15) }",
+ "{ (asm DUP16) }",
+ "{ (asm SWAP1) }",
+ "{ (asm SWAP2) }",
+ "{ (asm SWAP3) }",
+ "{ (asm SWAP4) }",
+ "{ (asm SWAP5) }",
+ "{ (asm SWAP6) }",
+ "{ (asm SWAP7) }",
+ "{ (asm SWAP8) }",
+ "{ (asm SWAP9) }",
+ "{ (asm SWAP10) }",
+ "{ (asm SWAP11) }",
+ "{ (asm SWAP12) }",
+ "{ (asm SWAP13) }",
+ "{ (asm SWAP14) }",
+ "{ (asm SWAP15) }",
+ "{ (asm SWAP16) }",
+ "{ (asm LOG0) }",
+ "{ (asm LOG1) }",
+ "{ (asm LOG2) }",
+ "{ (asm LOG3) }",
+ "{ (asm LOG4) }",
+ "{ (asm CREATE) }",
+ "{ (asm CALL) }",
+ "{ (asm CALLCODE) }",
+ "{ (asm RETURN) }",
+ "{ (asm DELEGATECALL) }",
+ "{ (asm STATICCALL) }",
+ "{ (asm REVERT) }",
+ "{ (asm INVALID) }",
+ "{ (asm SELFDESTRUCT) }"
+ };
+
+ for (size_t i = 0; i < opcodes_bytecode.size(); i++) {
+ vector<string> errors;
+ bytes code = eth::compileLLL(opcodes_lll[i], false, &errors);
+
+ BOOST_REQUIRE_MESSAGE(errors.empty(), opcodes_lll[i]);
+
+ BOOST_CHECK_EQUAL(toHex(code), opcodes_bytecode[i]);
+ }
+}
+
BOOST_AUTO_TEST_SUITE_END()
}
diff --git a/test/libsolidity/AnalysisFramework.cpp b/test/libsolidity/AnalysisFramework.cpp
index 3bdc40a0..ea9703ea 100644
--- a/test/libsolidity/AnalysisFramework.cpp
+++ b/test/libsolidity/AnalysisFramework.cpp
@@ -81,7 +81,7 @@ AnalysisFramework::parseAnalyseAndReturnError(
}
}
- return make_pair(&m_compiler.ast(), firstError);
+ return make_pair(&m_compiler.ast(""), firstError);
}
SourceUnit const* AnalysisFramework::parseAndAnalyse(string const& _source)
diff --git a/test/libsolidity/Assembly.cpp b/test/libsolidity/Assembly.cpp
index 56ac8cf5..358d3c72 100644
--- a/test/libsolidity/Assembly.cpp
+++ b/test/libsolidity/Assembly.cpp
@@ -119,7 +119,7 @@ BOOST_AUTO_TEST_CASE(location_test)
shared_ptr<string const> n = make_shared<string>("");
AssemblyItems items = compileContract(sourceCode);
vector<SourceLocation> locations =
- vector<SourceLocation>(18, SourceLocation(2, 75, n)) +
+ vector<SourceLocation>(24, SourceLocation(2, 75, n)) +
vector<SourceLocation>(32, SourceLocation(20, 72, n)) +
vector<SourceLocation>{SourceLocation(42, 51, n), SourceLocation(65, 67, n)} +
vector<SourceLocation>(2, SourceLocation(58, 67, n)) +
diff --git a/test/libsolidity/GasMeter.cpp b/test/libsolidity/GasMeter.cpp
index c2886f5b..86e8201b 100644
--- a/test/libsolidity/GasMeter.cpp
+++ b/test/libsolidity/GasMeter.cpp
@@ -51,8 +51,8 @@ public:
m_compiler.setOptimiserSettings(dev::test::Options::get().optimize);
BOOST_REQUIRE_MESSAGE(m_compiler.compile(), "Compiling contract failed");
- AssemblyItems const* items = m_compiler.runtimeAssemblyItems("");
- ASTNode const& sourceUnit = m_compiler.ast();
+ AssemblyItems const* items = m_compiler.runtimeAssemblyItems(m_compiler.lastContractName());
+ ASTNode const& sourceUnit = m_compiler.ast("");
BOOST_REQUIRE(items != nullptr);
m_gasCosts = GasEstimator::breakToStatementLevel(
GasEstimator::structuralEstimation(*items, vector<ASTNode const*>({&sourceUnit})),
@@ -64,13 +64,13 @@ public:
{
compileAndRun(_sourceCode);
auto state = make_shared<KnownState>();
- PathGasMeter meter(*m_compiler.assemblyItems());
+ PathGasMeter meter(*m_compiler.assemblyItems(m_compiler.lastContractName()));
GasMeter::GasConsumption gas = meter.estimateMax(0, state);
- u256 bytecodeSize(m_compiler.runtimeObject().bytecode.size());
+ u256 bytecodeSize(m_compiler.runtimeObject(m_compiler.lastContractName()).bytecode.size());
// costs for deployment
gas += bytecodeSize * GasCosts::createDataGas;
// costs for transaction
- gas += gasForTransaction(m_compiler.object().bytecode, true);
+ gas += gasForTransaction(m_compiler.object(m_compiler.lastContractName()).bytecode, true);
BOOST_REQUIRE(!gas.isInfinite);
BOOST_CHECK(gas.value == m_gasUsed);
@@ -91,7 +91,7 @@ public:
}
gas += GasEstimator::functionalEstimation(
- *m_compiler.runtimeAssemblyItems(),
+ *m_compiler.runtimeAssemblyItems(m_compiler.lastContractName()),
_sig
);
BOOST_REQUIRE(!gas.isInfinite);
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(non_overlapping_filtered_costs)
if (first->first->location().intersects(second->first->location()))
{
BOOST_CHECK_MESSAGE(false, "Source locations should not overlap!");
- auto scannerFromSource = [&](string const&) -> Scanner const& { return m_compiler.scanner(); };
+ auto scannerFromSource = [&](string const& _sourceName) -> Scanner const& { return m_compiler.scanner(_sourceName); };
SourceReferenceFormatter::printSourceLocation(cout, &first->first->location(), scannerFromSource);
SourceReferenceFormatter::printSourceLocation(cout, &second->first->location(), scannerFromSource);
}
diff --git a/test/libsolidity/SolidityABIJSON.cpp b/test/libsolidity/SolidityABIJSON.cpp
index 42f7525f..33962730 100644
--- a/test/libsolidity/SolidityABIJSON.cpp
+++ b/test/libsolidity/SolidityABIJSON.cpp
@@ -46,7 +46,7 @@ public:
m_compilerStack.addSource("", "pragma solidity >=0.0;\n" + _code);
BOOST_REQUIRE_MESSAGE(m_compilerStack.parseAndAnalyze(), "Parsing contract failed");
- Json::Value generatedInterface = m_compilerStack.contractABI("");
+ Json::Value generatedInterface = m_compilerStack.contractABI(m_compilerStack.lastContractName());
Json::Value expectedInterface;
BOOST_REQUIRE(m_reader.parse(_expectedInterfaceString, expectedInterface));
BOOST_CHECK_MESSAGE(
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index 648c13cb..9a837113 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -2899,6 +2899,25 @@ BOOST_AUTO_TEST_CASE(default_fallback_throws)
ABI_CHECK(callContractFunction("f()"), encodeArgs(0));
}
+BOOST_AUTO_TEST_CASE(short_data_calls_fallback)
+{
+ char const* sourceCode = R"(
+ contract A {
+ uint public x;
+ // Signature is d88e0b00
+ function fow() { x = 3; }
+ function () { x = 2; }
+ }
+ )";
+ compileAndRun(sourceCode);
+ // should call fallback
+ sendMessage(asBytes("\xd8\x8e\x0b"), false, 0);
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(2));
+ // should call function
+ sendMessage(asBytes(string("\xd8\x8e\x0b") + string(1, 0)), false, 0);
+ ABI_CHECK(callContractFunction("x()"), encodeArgs(3));
+}
+
BOOST_AUTO_TEST_CASE(event)
{
char const* sourceCode = R"(
diff --git a/test/libsolidity/SolidityExecutionFramework.h b/test/libsolidity/SolidityExecutionFramework.h
index 342d0875..b0daaba9 100644
--- a/test/libsolidity/SolidityExecutionFramework.h
+++ b/test/libsolidity/SolidityExecutionFramework.h
@@ -69,7 +69,7 @@ public:
);
BOOST_ERROR("Compiling contract failed");
}
- eth::LinkerObject obj = m_compiler.object(_contractName);
+ eth::LinkerObject obj = m_compiler.object(_contractName.empty() ? m_compiler.lastContractName() : _contractName);
BOOST_REQUIRE(obj.linkReferences.empty());
sendMessage(obj.bytecode + _arguments, true, _value);
return m_output;
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 2c720d03..e5990e9b 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -4783,6 +4783,16 @@ BOOST_AUTO_TEST_CASE(warn_about_callcode)
}
)";
CHECK_WARNING(text, "\"callcode\" has been deprecated in favour of \"delegatecall\"");
+ text = R"(
+ pragma experimental "v0.5.0";
+ contract test {
+ function f() pure public {
+ var x = address(0x12).callcode;
+ x;
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "\"callcode\" has been deprecated in favour of \"delegatecall\"");
}
BOOST_AUTO_TEST_CASE(no_warn_about_callcode_as_function)
@@ -5537,7 +5547,7 @@ BOOST_AUTO_TEST_CASE(invalid_mobile_type)
}
}
)";
- CHECK_ERROR(text, TypeError, "Invalid mobile type.");
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
}
BOOST_AUTO_TEST_CASE(warns_msg_value_in_non_payable_public_function)
@@ -7096,6 +7106,53 @@ BOOST_AUTO_TEST_CASE(non_external_fallback)
CHECK_ERROR(text, TypeError, "Fallback function must be defined as \"external\".");
}
+BOOST_AUTO_TEST_CASE(invalid_literal_in_tuple)
+{
+ char const* text = R"(
+ contract C {
+ function f() pure public {
+ uint x;
+ (x, ) = (1E111);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "is not implicitly convertible to expected type");
+ text = R"(
+ contract C {
+ function f() pure public {
+ uint x;
+ (x, ) = (1, 1E111);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
+ text = R"(
+ contract C {
+ function f() pure public {
+ uint x;
+ (x, ) = (1E111, 1);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
+ text = R"(
+ contract C {
+ function f() pure public {
+ (2**270, 1);
+ }
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Invalid rational number.");
+ text = R"(
+ contract C {
+ function f() pure public {
+ ((2**270) / 2**100, 1);
+ }
+ }
+ )";
+ CHECK_SUCCESS(text);
+}
+
BOOST_AUTO_TEST_CASE(warn_about_sha3)
{
char const* text = R"(
@@ -7190,6 +7247,12 @@ BOOST_AUTO_TEST_CASE(array_length_invalid_expression)
}
)";
CHECK_ERROR(text, TypeError, "Invalid literal value.");
+ text = R"(
+ contract C {
+ uint[3/0] ids;
+ }
+ )";
+ CHECK_ERROR(text, TypeError, "Operator / not compatible with types int_const 3 and int_const 0");
}
BOOST_AUTO_TEST_CASE(no_address_members_on_contract)
diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp
index d83773bc..fb09451f 100644
--- a/test/libsolidity/SolidityNatspecJSON.cpp
+++ b/test/libsolidity/SolidityNatspecJSON.cpp
@@ -51,9 +51,9 @@ public:
Json::Value generatedDocumentation;
if (_userDocumentation)
- generatedDocumentation = m_compilerStack.natspecUser("");
+ generatedDocumentation = m_compilerStack.natspecUser(m_compilerStack.lastContractName());
else
- generatedDocumentation = m_compilerStack.natspecDev("");
+ generatedDocumentation = m_compilerStack.natspecDev(m_compilerStack.lastContractName());
Json::Value expectedDocumentation;
m_reader.parse(_expectedDocumentationString, expectedDocumentation);
BOOST_CHECK_MESSAGE(