Check for circular constants across contracts.

This commit is contained in:
chriseth 2020-09-29 16:23:45 +02:00
parent c4d8b4fa0e
commit 21dee1c8ba
3 changed files with 36 additions and 10 deletions

View File

@ -38,6 +38,13 @@ bool PostTypeChecker::check(ASTNode const& _astRoot)
return Error::containsOnlyWarnings(m_errorReporter.errors()); return Error::containsOnlyWarnings(m_errorReporter.errors());
} }
bool PostTypeChecker::finalize()
{
for (auto& checker: m_checkers)
checker->finalize();
return Error::containsOnlyWarnings(m_errorReporter.errors());
}
bool PostTypeChecker::visit(ContractDefinition const& _contractDefinition) bool PostTypeChecker::visit(ContractDefinition const& _contractDefinition)
{ {
return callVisit(_contractDefinition); return callVisit(_contractDefinition);
@ -83,6 +90,11 @@ bool PostTypeChecker::visit(Identifier const& _identifier)
return callVisit(_identifier); return callVisit(_identifier);
} }
bool PostTypeChecker::visit(MemberAccess const& _memberAccess)
{
return callVisit(_memberAccess);
}
bool PostTypeChecker::visit(StructDefinition const& _struct) bool PostTypeChecker::visit(StructDefinition const& _struct)
{ {
return callVisit(_struct); return callVisit(_struct);
@ -110,14 +122,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
ConstStateVarCircularReferenceChecker(ErrorReporter& _errorReporter): ConstStateVarCircularReferenceChecker(ErrorReporter& _errorReporter):
Checker(_errorReporter) {} Checker(_errorReporter) {}
bool visit(ContractDefinition const&) override void finalize() override
{
solAssert(!m_currentConstVariable, "");
solAssert(m_constVariableDependencies.empty(), "");
return true;
}
void endVisit(ContractDefinition const&) override
{ {
solAssert(!m_currentConstVariable, ""); solAssert(!m_currentConstVariable, "");
for (auto declaration: m_constVariables) for (auto declaration: m_constVariables)
@ -128,9 +133,12 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
"The value of the constant " + declaration->name() + "The value of the constant " + declaration->name() +
" has a cyclic dependency via " + identifier->name() + "." " has a cyclic dependency via " + identifier->name() + "."
); );
}
m_constVariables.clear(); bool visit(ContractDefinition const&) override
m_constVariableDependencies.clear(); {
solAssert(!m_currentConstVariable, "");
return true;
} }
bool visit(VariableDeclaration const& _variable) override bool visit(VariableDeclaration const& _variable) override
@ -162,6 +170,15 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
return true; return true;
} }
bool visit(MemberAccess const& _memberAccess) override
{
if (m_currentConstVariable)
if (auto var = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
if (var->isConstant())
m_constVariableDependencies[m_currentConstVariable].insert(var);
return true;
}
VariableDeclaration const* findCycle(VariableDeclaration const& _startingFrom) VariableDeclaration const* findCycle(VariableDeclaration const& _startingFrom)
{ {
auto visitor = [&](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth) auto visitor = [&](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)

View File

@ -54,6 +54,9 @@ public:
{ {
Checker(langutil::ErrorReporter& _errorReporter): Checker(langutil::ErrorReporter& _errorReporter):
m_errorReporter(_errorReporter) {} m_errorReporter(_errorReporter) {}
/// Called after all source units have been visited.
virtual void finalize() {}
protected: protected:
langutil::ErrorReporter& m_errorReporter; langutil::ErrorReporter& m_errorReporter;
}; };
@ -63,6 +66,9 @@ public:
bool check(ASTNode const& _astRoot); bool check(ASTNode const& _astRoot);
/// Called after all source units have been visited.
bool finalize();
private: private:
bool visit(ContractDefinition const& _contract) override; bool visit(ContractDefinition const& _contract) override;
void endVisit(ContractDefinition const& _contract) override; void endVisit(ContractDefinition const& _contract) override;
@ -77,6 +83,7 @@ private:
bool visit(FunctionCall const& _functionCall) override; bool visit(FunctionCall const& _functionCall) override;
bool visit(Identifier const& _identifier) override; bool visit(Identifier const& _identifier) override;
bool visit(MemberAccess const& _identifier) override;
bool visit(StructDefinition const& _struct) override; bool visit(StructDefinition const& _struct) override;
void endVisit(StructDefinition const& _struct) override; void endVisit(StructDefinition const& _struct) override;

View File

@ -387,6 +387,8 @@ bool CompilerStack::analyze()
for (Source const* source: m_sourceOrder) for (Source const* source: m_sourceOrder)
if (source->ast && !postTypeChecker.check(*source->ast)) if (source->ast && !postTypeChecker.check(*source->ast))
noErrors = false; noErrors = false;
if (!postTypeChecker.finalize())
noErrors = false;
} }
// Check that immutable variables are never read in c'tors and assigned // Check that immutable variables are never read in c'tors and assigned