From d102deaec90f6f5bfe38140b459a05215d3254f9 Mon Sep 17 00:00:00 2001
From: Balajiganapathi S <balajiganapathi.s@gmail.com>
Date: Fri, 17 Nov 2017 22:25:07 +0530
Subject: Detect cyclic constant definitions

---
 libsolidity/analysis/ConstantEvaluator.cpp         | 16 +++++++-----
 libsolidity/analysis/ConstantEvaluator.h           |  7 +++--
 test/libsolidity/SolidityNameAndTypeResolution.cpp | 30 +++++++++++++++++++++-
 3 files changed, 44 insertions(+), 9 deletions(-)

diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index 50044eb6..cb8bbc05 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -77,18 +77,22 @@ void ConstantEvaluator::endVisit(Literal const& _literal)
 
 void ConstantEvaluator::endVisit(Identifier const& _identifier)
 {
-	VariableDeclaration const *variableDeclaration = dynamic_cast<VariableDeclaration const *>(_identifier.annotation().referencedDeclaration);
+	VariableDeclaration const* variableDeclaration = dynamic_cast<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration);
 	if (!variableDeclaration)
 		return;
 	if (!variableDeclaration->isConstant())
 		m_errorReporter.fatalTypeError(_identifier.location(), "Identifier must be declared constant.");
 
 	ASTPointer<Expression> value = variableDeclaration->value();
-	if (value)
-	{
-		if (!value->annotation().type)
-			ConstantEvaluator e(*value, m_errorReporter);
+	if (!value)
+		m_errorReporter.fatalTypeError(_identifier.location(), "Constant identifier declaration must have a constant value.");
 
-		_identifier.annotation().type = value->annotation().type;
+	if (!value->annotation().type)
+	{
+		if (m_depth > 32)
+			m_errorReporter.fatalTypeError(_identifier.location(), "Cyclic constant definition.");
+		ConstantEvaluator e(*value, m_errorReporter, m_depth + 1);
 	}
+
+	_identifier.annotation().type = value->annotation().type;
 }
diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h
index 42ccfe7e..6725d610 100644
--- a/libsolidity/analysis/ConstantEvaluator.h
+++ b/libsolidity/analysis/ConstantEvaluator.h
@@ -38,8 +38,9 @@ class TypeChecker;
 class ConstantEvaluator: private ASTConstVisitor
 {
 public:
-	ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter):
-		m_errorReporter(_errorReporter)
+	ConstantEvaluator(Expression const& _expr, ErrorReporter& _errorReporter, size_t _newDepth = 0):
+		m_errorReporter(_errorReporter),
+		m_depth(_newDepth)
 	{
 		_expr.accept(*this);
 	}
@@ -51,6 +52,8 @@ private:
 	virtual void endVisit(Identifier const& _identifier);
 
 	ErrorReporter& m_errorReporter;
+	/// Current recursion depth.
+	size_t m_depth;
 };
 
 }
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index cedf7f3a..0d02ac34 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -7366,7 +7366,35 @@ BOOST_AUTO_TEST_CASE(array_length_cannot_be_constant_function_parameter)
 			}
 		}
 	)";
-	CHECK_ERROR(text, TypeError, "Invalid array length, expected integer literal.");
+	CHECK_ERROR(text, TypeError, "Constant identifier declaration must have a constant value.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_with_cyclic_constant)
+{
+	char const* text = R"(
+		contract C {
+			uint constant LEN = LEN;
+			function f() {
+				uint[LEN] a;
+			}
+		}
+	)";
+	CHECK_ERROR(text, TypeError, "Cyclic constant definition.");
+}
+
+BOOST_AUTO_TEST_CASE(array_length_with_complex_cyclic_constant)
+{
+	char const* text = R"(
+		contract C {
+			uint constant L2 = LEN - 10;
+			uint constant L1 = L2 / 10;
+			uint constant LEN = 10 + L1 * 5;
+			function f() {
+				uint[LEN] a;
+			}
+		}
+	)";
+	CHECK_ERROR(text, TypeError, "Cyclic constant definition.");
 }
 
 BOOST_AUTO_TEST_CASE(array_length_with_pure_functions)
-- 
cgit v1.2.3