aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2019-01-18 07:16:06 +0800
committerGitHub <noreply@github.com>2019-01-18 07:16:06 +0800
commit2ec997e697e306dd54165aad365406ee88c534cb (patch)
tree5e943e23d38e332de3eedd33be11f2cf9df5fd69 /libsolidity/analysis
parent0711873a2f13d7b0f27e268fcd0a7683665f339d (diff)
parent2a92403690a4998ab097503231ac39f854b9c76c (diff)
downloaddexon-solidity-2ec997e697e306dd54165aad365406ee88c534cb.tar.gz
dexon-solidity-2ec997e697e306dd54165aad365406ee88c534cb.tar.zst
dexon-solidity-2ec997e697e306dd54165aad365406ee88c534cb.zip
Merge pull request #5775 from ethereum/codeAccess
Provide access to code of contract types.
Diffstat (limited to 'libsolidity/analysis')
-rw-r--r--libsolidity/analysis/GlobalContext.cpp9
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp62
-rw-r--r--libsolidity/analysis/StaticAnalyzer.h9
-rw-r--r--libsolidity/analysis/TypeChecker.cpp51
-rw-r--r--libsolidity/analysis/TypeChecker.h2
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp4
6 files changed, 134 insertions, 3 deletions
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp
index cd5fe07d..2276d783 100644
--- a/libsolidity/analysis/GlobalContext.cpp
+++ b/libsolidity/analysis/GlobalContext.cpp
@@ -61,7 +61,14 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{
make_shared<MagicVariableDeclaration>("sha256", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::SHA256, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("sha3", make_shared<FunctionType>(strings{"bytes memory"}, strings{"bytes32"}, FunctionType::Kind::KECCAK256, false, StateMutability::Pure)),
make_shared<MagicVariableDeclaration>("suicide", make_shared<FunctionType>(strings{"address payable"}, strings{}, FunctionType::Kind::Selfdestruct)),
- make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction))
+ make_shared<MagicVariableDeclaration>("tx", make_shared<MagicType>(MagicType::Kind::Transaction)),
+ make_shared<MagicVariableDeclaration>("type", make_shared<FunctionType>(
+ strings{"address"} /* accepts any contract type, handled by the type checker */,
+ strings{} /* returns a MagicType, handled by the type checker */,
+ FunctionType::Kind::MetaType,
+ false,
+ StateMutability::Pure
+ )),
})
{
}
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index aaaa4f9f..11ed6a4f 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -32,6 +32,56 @@ using namespace dev;
using namespace langutil;
using namespace dev::solidity;
+/**
+ * Helper class that determines whether a contract's constructor uses inline assembly.
+ */
+class dev::solidity::ConstructorUsesAssembly
+{
+public:
+ /// @returns true if and only if the contract's or any of its bases' constructors
+ /// use inline assembly.
+ bool check(ContractDefinition const& _contract)
+ {
+ for (auto const* base: _contract.annotation().linearizedBaseContracts)
+ if (checkInternal(*base))
+ return true;
+ return false;
+ }
+
+
+private:
+ class Checker: public ASTConstVisitor
+ {
+ public:
+ Checker(FunctionDefinition const& _f) { _f.accept(*this); }
+ bool visit(InlineAssembly const&) override { assemblySeen = true; return false; }
+ bool assemblySeen = false;
+ };
+
+ bool checkInternal(ContractDefinition const& _contract)
+ {
+ if (!m_usesAssembly.count(&_contract))
+ {
+ bool usesAssembly = false;
+ if (_contract.constructor())
+ usesAssembly = Checker{*_contract.constructor()}.assemblySeen;
+ m_usesAssembly[&_contract] = usesAssembly;
+ }
+ return m_usesAssembly[&_contract];
+ }
+
+ map<ContractDefinition const*, bool> m_usesAssembly;
+};
+
+StaticAnalyzer::StaticAnalyzer(ErrorReporter& _errorReporter):
+ m_errorReporter(_errorReporter)
+{
+}
+
+StaticAnalyzer::~StaticAnalyzer()
+{
+}
+
bool StaticAnalyzer::analyze(SourceUnit const& _sourceUnit)
{
_sourceUnit.accept(*this);
@@ -152,6 +202,18 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
_memberAccess.location(),
"\"block.blockhash()\" has been deprecated in favor of \"blockhash()\""
);
+ else if (type->kind() == MagicType::Kind::MetaType && _memberAccess.memberName() == "runtimeCode")
+ {
+ if (!m_constructorUsesAssembly)
+ m_constructorUsesAssembly = make_unique<ConstructorUsesAssembly>();
+ ContractType const& contract = dynamic_cast<ContractType const&>(*type->typeArgument());
+ if (m_constructorUsesAssembly->check(contract.contractDefinition()))
+ m_errorReporter.warning(
+ _memberAccess.location(),
+ "The constructor of the contract (or its base) uses inline assembly. "
+ "Because of that, it might be that the deployed bytecode is different from type(...).runtimeCode."
+ );
+ }
}
if (_memberAccess.memberName() == "callcode")
diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h
index ff33fa3a..3daf83b3 100644
--- a/libsolidity/analysis/StaticAnalyzer.h
+++ b/libsolidity/analysis/StaticAnalyzer.h
@@ -38,6 +38,8 @@ namespace dev
namespace solidity
{
+class ConstructorUsesAssembly;
+
/**
* The module that performs static analysis on the AST.
@@ -49,7 +51,8 @@ class StaticAnalyzer: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- explicit StaticAnalyzer(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ explicit StaticAnalyzer(langutil::ErrorReporter& _errorReporter);
+ ~StaticAnalyzer();
/// Performs static analysis on the given source unit and all of its sub-nodes.
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
@@ -85,6 +88,10 @@ private:
/// when traversing.
std::map<std::pair<size_t, VariableDeclaration const*>, int> m_localVarUseCount;
+ /// Cache that holds information about whether a contract's constructor
+ /// uses inline assembly.
+ std::unique_ptr<ConstructorUsesAssembly> m_constructorUsesAssembly;
+
FunctionDefinition const* m_currentFunction = nullptr;
/// Flag that indicates a constructor.
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index 7fa9933c..d038233c 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -199,6 +199,38 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
return components;
}
+TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall)
+{
+ vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
+ if (arguments.size() != 1)
+ {
+ m_errorReporter.typeError(
+ _functionCall.location(),
+ "This function takes one argument, but " +
+ toString(arguments.size()) +
+ " were provided."
+ );
+ return {};
+ }
+ TypePointer firstArgType = type(*arguments.front());
+ if (
+ firstArgType->category() != Type::Category::TypeType ||
+ dynamic_cast<TypeType const&>(*firstArgType).actualType()->category() != TypeType::Category::Contract
+ )
+ {
+ m_errorReporter.typeError(
+ arguments.front()->location(),
+ "Invalid type for argument in function call. "
+ "Contract type required, but " +
+ type(*arguments.front())->toString(true) +
+ " provided."
+ );
+ return {};
+ }
+
+ return {MagicType::metaType(dynamic_cast<TypeType const&>(*firstArgType).actualType())};
+}
+
void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
{
auto base = dynamic_cast<ContractDefinition const*>(&dereference(_inheritance.name()));
@@ -1831,6 +1863,9 @@ bool TypeChecker::visit(FunctionCall const& _functionCall)
returnTypes = functionType->returnParameterTypes();
break;
}
+ case FunctionType::Kind::MetaType:
+ returnTypes = typeCheckMetaTypeFunctionAndRetrieveReturnType(_functionCall);
+ break;
default:
{
typeCheckFunctionCall(_functionCall, functionType);
@@ -2071,8 +2106,24 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
if (tt->actualType()->category() == Type::Category::Enum)
annotation.isPure = true;
if (auto magicType = dynamic_cast<MagicType const*>(exprType.get()))
+ {
if (magicType->kind() == MagicType::Kind::ABI)
annotation.isPure = true;
+ else if (magicType->kind() == MagicType::Kind::MetaType && (
+ memberName == "creationCode" || memberName == "runtimeCode"
+ ))
+ {
+ annotation.isPure = true;
+ m_scope->annotation().contractDependencies.insert(
+ &dynamic_cast<ContractType const&>(*magicType->typeArgument()).contractDefinition()
+ );
+ if (contractDependenciesAreCyclic(*m_scope))
+ m_errorReporter.typeError(
+ _memberAccess.location(),
+ "Circular reference for contract code access."
+ );
+ }
+ }
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index b60c571a..d5f3645c 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -81,6 +81,8 @@ private:
bool _abiEncoderV2
);
+ TypePointers typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall);
+
/// Performs type checks and determines result types for type conversion FunctionCall nodes.
TypePointer typeCheckTypeConversionAndRetrieveReturnType(
FunctionCall const& _functionCall
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index eb019481..7df7ac17 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -338,7 +338,9 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::ABI, "encodeWithSignature"},
{MagicType::Kind::Block, "blockhash"},
{MagicType::Kind::Message, "data"},
- {MagicType::Kind::Message, "sig"}
+ {MagicType::Kind::Message, "sig"},
+ {MagicType::Kind::MetaType, "creationCode"},
+ {MagicType::Kind::MetaType, "runtimeCode"}
};
set<MagicMember> static const payableMembers{
{MagicType::Kind::Message, "value"}