aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2017-08-31 19:13:35 +0800
committerchriseth <chris@ethereum.org>2017-09-06 19:52:29 +0800
commitd6861d909c7dabb6993cfa7a8269f76c613428f7 (patch)
treefd3da3822fb4d9a4ee2d615960109b764cfb876e
parent7c61a6daf2052afaba86ad52623028cc8e14572b (diff)
downloaddexon-solidity-d6861d909c7dabb6993cfa7a8269f76c613428f7.tar.gz
dexon-solidity-d6861d909c7dabb6993cfa7a8269f76c613428f7.tar.zst
dexon-solidity-d6861d909c7dabb6993cfa7a8269f76c613428f7.zip
Analyze assembly.
-rw-r--r--libevmasm/SemanticInformation.cpp1
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp97
-rw-r--r--libsolidity/analysis/ViewPureChecker.h2
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp4
-rw-r--r--test/libsolidity/ViewPureChecker.cpp62
5 files changed, 153 insertions, 13 deletions
diff --git a/libevmasm/SemanticInformation.cpp b/libevmasm/SemanticInformation.cpp
index abe47e10..ceb3fbdd 100644
--- a/libevmasm/SemanticInformation.cpp
+++ b/libevmasm/SemanticInformation.cpp
@@ -207,6 +207,7 @@ bool SemanticInformation::invalidInPureFunctions(Instruction _instruction)
case Instruction::NUMBER:
case Instruction::DIFFICULTY:
case Instruction::GASLIMIT:
+ case Instruction::STATICCALL:
case Instruction::SLOAD:
return true;
default:
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index b4b7f372..60b07297 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -17,10 +17,86 @@
#include <libsolidity/analysis/ViewPureChecker.h>
+#include <libevmasm/SemanticInformation.h>
+
+#include <libsolidity/inlineasm/AsmData.h>
+
+#include <functional>
+
using namespace std;
using namespace dev;
using namespace dev::solidity;
+
+class AssemblyViewPureChecker: public boost::static_visitor<void>
+{
+public:
+ explicit AssemblyViewPureChecker(std::function<void(StateMutability, SourceLocation const&)> _reportMutability):
+ m_reportMutability(_reportMutability) {}
+
+ void operator()(assembly::Label const&) { }
+ void operator()(assembly::Instruction const& _instruction)
+ {
+ if (eth::SemanticInformation::invalidInViewFunctions(_instruction.instruction))
+ m_reportMutability(StateMutability::NonPayable, _instruction.location);
+ else if (eth::SemanticInformation::invalidInPureFunctions(_instruction.instruction))
+ m_reportMutability(StateMutability::View, _instruction.location);
+ }
+ void operator()(assembly::Literal const&) {}
+ void operator()(assembly::Identifier const&) {}
+ void operator()(assembly::FunctionalInstruction const& _instr)
+ {
+ (*this)(_instr.instruction);
+ for (auto const& arg: _instr.arguments)
+ boost::apply_visitor(*this, arg);
+ }
+ void operator()(assembly::StackAssignment const&) {}
+ void operator()(assembly::Assignment const& _assignment)
+ {
+ boost::apply_visitor(*this, *_assignment.value);
+ }
+ void operator()(assembly::VariableDeclaration const& _varDecl)
+ {
+ if (_varDecl.value)
+ boost::apply_visitor(*this, *_varDecl.value);
+ }
+ void operator()(assembly::FunctionDefinition const& _funDef)
+ {
+ (*this)(_funDef.body);
+ }
+ void operator()(assembly::FunctionCall const& _funCall)
+ {
+ for (auto const& arg: _funCall.arguments)
+ boost::apply_visitor(*this, arg);
+ }
+ void operator()(assembly::Switch const& _switch)
+ {
+ boost::apply_visitor(*this, *_switch.expression);
+ for (auto const& _case: _switch.cases)
+ {
+ if (_case.value)
+ (*this)(*_case.value);
+ (*this)(_case.body);
+ }
+ }
+ void operator()(assembly::ForLoop const& _for)
+ {
+ (*this)(_for.pre);
+ boost::apply_visitor(*this, *_for.condition);
+ (*this)(_for.body);
+ (*this)(_for.post);
+ }
+ void operator()(assembly::Block const& _block)
+ {
+ for (auto const& s: _block.statements)
+ boost::apply_visitor(*this, s);
+ }
+
+private:
+ std::function<void(StateMutability, SourceLocation const&)> m_reportMutability;
+};
+
+
bool ViewPureChecker::check()
{
vector<ContractDefinition const*> contracts;
@@ -122,16 +198,17 @@ void ViewPureChecker::endVisit(Identifier const& _identifier)
}
}
- reportMutability(mutability, _identifier);
+ reportMutability(mutability, _identifier.location());
}
void ViewPureChecker::endVisit(InlineAssembly const& _inlineAssembly)
{
- // @TOOD we can and should analyze it further.
- reportMutability(StateMutability::NonPayable, _inlineAssembly);
+ AssemblyViewPureChecker{
+ [=](StateMutability _mut, SourceLocation const& _loc) { reportMutability(_mut, _loc); }
+ }(_inlineAssembly.operations());
}
-void ViewPureChecker::reportMutability(StateMutability _mutability, ASTNode const& _node)
+void ViewPureChecker::reportMutability(StateMutability _mutability, SourceLocation const& _location)
{
if (m_currentFunction && m_currentFunction->stateMutability() < _mutability)
{
@@ -151,11 +228,11 @@ void ViewPureChecker::reportMutability(StateMutability _mutability, ASTNode cons
if (m_currentFunction->stateMutability() == StateMutability::View)
// Change this to error with 0.5.0
- m_errorReporter.warning(_node.location(), text);
+ m_errorReporter.warning(_location, text);
else if (m_currentFunction->stateMutability() == StateMutability::Pure)
{
m_errors = true;
- m_errorReporter.typeError(_node.location(), text);
+ m_errorReporter.typeError(_location, text);
}
else
solAssert(false, "");
@@ -173,7 +250,7 @@ void ViewPureChecker::endVisit(FunctionCall const& _functionCall)
// We only require "nonpayable" to call a payble function.
if (mut == StateMutability::Payable)
mut = StateMutability::NonPayable;
- reportMutability(mut, _functionCall);
+ reportMutability(mut, _functionCall.location());
}
void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
@@ -210,7 +287,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
default:
break;
}
- reportMutability(mutability, _memberAccess);
+ reportMutability(mutability, _memberAccess.location());
}
void ViewPureChecker::endVisit(IndexAccess const& _indexAccess)
@@ -219,7 +296,7 @@ void ViewPureChecker::endVisit(IndexAccess const& _indexAccess)
bool writes = _indexAccess.annotation().lValueRequested;
if (_indexAccess.baseExpression().annotation().type->dataStoredIn(DataLocation::Storage))
- reportMutability(writes ? StateMutability::NonPayable : StateMutability::View, _indexAccess);
+ reportMutability(writes ? StateMutability::NonPayable : StateMutability::View, _indexAccess.location());
}
void ViewPureChecker::endVisit(ModifierInvocation const& _modifier)
@@ -229,6 +306,6 @@ void ViewPureChecker::endVisit(ModifierInvocation const& _modifier)
solAssert(mod, "");
solAssert(m_inferredMutability.count(mod), "");
- reportMutability(m_inferredMutability.at(mod), _modifier);
+ reportMutability(m_inferredMutability.at(mod), _modifier.location());
}
diff --git a/libsolidity/analysis/ViewPureChecker.h b/libsolidity/analysis/ViewPureChecker.h
index 6aedfa36..ae303533 100644
--- a/libsolidity/analysis/ViewPureChecker.h
+++ b/libsolidity/analysis/ViewPureChecker.h
@@ -64,7 +64,7 @@ private:
/// Called when an element of mutability @a _mutability is encountered.
/// Creates appropriate warnings and errors and sets @a m_currentBestMutability.
- void reportMutability(StateMutability _mutability, ASTNode const& _node);
+ void reportMutability(StateMutability _mutability, SourceLocation const& _location);
std::vector<std::shared_ptr<ASTNode>> const& m_ast;
ErrorReporter& m_errorReporter;
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 800f102b..6886fcd0 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -5234,7 +5234,7 @@ BOOST_AUTO_TEST_CASE(inline_assembly_storage_variable_access_out_of_functions)
char const* text = R"(
contract test {
uint a;
- function f() {
+ function f() pure {
assembly {
function g() -> x { x := a_slot }
}
@@ -5921,7 +5921,7 @@ BOOST_AUTO_TEST_CASE(no_unused_inline_asm)
{
char const* text = R"(
contract C {
- function f() {
+ function f() pure {
uint a;
assembly {
a := 1
diff --git a/test/libsolidity/ViewPureChecker.cpp b/test/libsolidity/ViewPureChecker.cpp
index 7099ffd7..fabd1bee 100644
--- a/test/libsolidity/ViewPureChecker.cpp
+++ b/test/libsolidity/ViewPureChecker.cpp
@@ -316,6 +316,68 @@ BOOST_AUTO_TEST_CASE(function_types)
CHECK_SUCCESS_NO_WARNINGS(text);
}
+BOOST_AUTO_TEST_CASE(creation)
+{
+ string text = R"(
+ contract D {}
+ contract C {
+ function f() { new D(); }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(assembly)
+{
+ string text = R"(
+ contract C {
+ struct S { uint x; }
+ S s;
+ function e() pure {
+ assembly { mstore(keccak256(0, 20), mul(s_slot, 2)) }
+ }
+ function f() pure {
+ uint x;
+ assembly { x := 7 }
+ }
+ function g() view {
+ assembly { for {} 1 { pop(sload(0)) } { } }
+ }
+ function h() view {
+ assembly { function g() { pop(blockhash(20)) } }
+ }
+ function j() {
+ assembly { pop(call(0, 1, 2, 3, 4, 5, 6)) }
+ }
+ }
+ )";
+ CHECK_SUCCESS_NO_WARNINGS(text);
+}
+
+BOOST_AUTO_TEST_CASE(assembly_staticcall)
+{
+ string text = R"(
+ contract C {
+ function i() view {
+ assembly { pop(staticcall(0, 1, 2, 3, 4, 5)) }
+ }
+ }
+ )";
+ CHECK_WARNING(text, "only available after the Metropolis");
+}
+
+BOOST_AUTO_TEST_CASE(assembly_jump)
+{
+ string text = R"(
+ contract C {
+ function k() {
+ assembly { jump(2) }
+ }
+ }
+ )";
+ CHECK_WARNING(text, "low-level EVM features");
+}
+
BOOST_AUTO_TEST_SUITE_END()
}