aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <c@ethdev.com>2015-09-15 22:23:06 +0800
committerchriseth <c@ethdev.com>2015-09-15 22:23:06 +0800
commit9d43f2c186d1ad4027d42f6b155bea5500efa0e5 (patch)
tree55116e80169b079fa80f41acd75707a252be880f
parent9de174ce2e8ec0952c6ea1113238299d82f14165 (diff)
parent152bc642a6e8025d7957898e25848c9c836eb462 (diff)
downloaddexon-solidity-9d43f2c186d1ad4027d42f6b155bea5500efa0e5.tar.gz
dexon-solidity-9d43f2c186d1ad4027d42f6b155bea5500efa0e5.tar.zst
dexon-solidity-9d43f2c186d1ad4027d42f6b155bea5500efa0e5.zip
Merge pull request #32 from LianaHus/sol_compiletime_check_for_out_of_bound_access_for_arrays
Sol compiletime check for out of bound index(integer constant) access for Ordinary arrays
-rw-r--r--libsolidity/AST.cpp86
-rw-r--r--libsolidity/ExpressionCompiler.cpp1
-rw-r--r--test/libsolidity/SolidityEndToEndTest.cpp5
-rw-r--r--test/libsolidity/SolidityNameAndTypeResolution.cpp15
4 files changed, 71 insertions, 36 deletions
diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp
index 674f33b7..daa84016 100644
--- a/libsolidity/AST.cpp
+++ b/libsolidity/AST.cpp
@@ -58,11 +58,11 @@ void ContractDefinition::checkTypeRequirements()
checkAbstractFunctions();
checkAbstractConstructors();
- FunctionDefinition const* function = constructor();
- if (function && !function->returnParameters().empty())
- BOOST_THROW_EXCEPTION(
- function->returnParameterList()->createTypeError("Non-empty \"returns\" directive for constructor.")
- );
+ FunctionDefinition const* functionDefinition = constructor();
+ if (functionDefinition && !functionDefinition->returnParameters().empty())
+ BOOST_THROW_EXCEPTION(functionDefinition->returnParameterList()->createTypeError(
+ "Non-empty \"returns\" directive for constructor."
+ ));
FunctionDefinition const* fallbackFunction = nullptr;
for (ASTPointer<FunctionDefinition> const& function: definedFunctions())
@@ -178,7 +178,9 @@ void ContractDefinition::checkDuplicateFunctions() const
errinfo_sourceLocation(overloads[j]->location()) <<
errinfo_comment("Function with same name and arguments defined twice.") <<
errinfo_secondarySourceLocation(SecondarySourceLocation().append(
- "Other declaration is here:", overloads[i]->location()))
+ "Other declaration is here:", overloads[i]->location())
+ )
+
);
}
}
@@ -767,8 +769,10 @@ void Return::checkTypeRequirements()
if (!m_returnParameters)
BOOST_THROW_EXCEPTION(createTypeError("Return arguments not allowed."));
if (m_returnParameters->parameters().size() != 1)
- BOOST_THROW_EXCEPTION(createTypeError("Different number of arguments in return statement "
- "than in returns declaration."));
+ BOOST_THROW_EXCEPTION(createTypeError(
+ "Different number of arguments in return statement "
+ "than in returns declaration."
+ ));
// this could later be changed such that the paramaters type is an anonymous struct type,
// but for now, we only allow one return parameter
m_expression->expectType(*m_returnParameters->parameters().front()->type());
@@ -795,10 +799,14 @@ void Assignment::checkTypeRequirements(TypePointers const*)
TypePointer resultType = m_type->binaryOperatorResult(Token::AssignmentToBinaryOp(m_assigmentOperator),
m_rightHandSide->type());
if (!resultType || *resultType != *m_type)
- BOOST_THROW_EXCEPTION(createTypeError("Operator " + string(Token::toString(m_assigmentOperator)) +
- " not compatible with types " +
- m_type->toString() + " and " +
- m_rightHandSide->type()->toString()));
+ BOOST_THROW_EXCEPTION(createTypeError(
+ "Operator " +
+ string(Token::toString(m_assigmentOperator)) +
+ " not compatible with types " +
+ m_type->toString() +
+ " and " +
+ m_rightHandSide->type()->toString()
+ ));
}
}
@@ -850,16 +858,13 @@ void BinaryOperation::checkTypeRequirements(TypePointers const*)
m_right->checkTypeRequirements(nullptr);
m_commonType = m_left->type()->binaryOperatorResult(m_operator, m_right->type());
if (!m_commonType)
- BOOST_THROW_EXCEPTION(
- createTypeError(
- "Operator " +
- string(Token::toString(m_operator)) +
- " not compatible with types " +
- m_left->type()->toString() +
- " and " +
- m_right->type()->toString()
- )
- );
+ BOOST_THROW_EXCEPTION(createTypeError(
+ "Operator " + string(Token::toString(m_operator)) +
+ " not compatible with types " +
+ m_left->type()->toString() +
+ " and " +
+ m_right->type()->toString()
+ ));
m_type = Token::isCompareOp(m_operator) ? make_shared<BoolType>() : m_commonType;
}
@@ -1040,7 +1045,8 @@ void NewExpression::checkTypeRequirements(TypePointers const*)
TypePointers{contractType},
strings(),
strings(),
- FunctionType::Location::Creation);
+ FunctionType::Location::Creation
+ );
}
void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
@@ -1069,19 +1075,25 @@ void MemberAccess::checkTypeRequirements(TypePointers const* _argumentTypes)
);
if (!storageType->members().membersByName(*m_memberName).empty())
BOOST_THROW_EXCEPTION(createTypeError(
- "Member \"" + *m_memberName + "\" is not available in " +
+ "Member \"" +
+ *m_memberName +
+ "\" is not available in " +
type.toString() +
" outside of storage."
));
BOOST_THROW_EXCEPTION(createTypeError(
- "Member \"" + *m_memberName + "\" not found or not visible "
- "after argument-dependent lookup in " + type.toString()
+ "Member \"" +
+ *m_memberName +
+ "\" not found or not visible after argument-dependent lookup in " +
+ type.toString()
));
}
else if (possibleMembers.size() > 1)
BOOST_THROW_EXCEPTION(createTypeError(
- "Member \"" + *m_memberName + "\" not unique "
- "after argument-dependent lookup in " + type.toString()
+ "Member \"" +
+ *m_memberName +
+ "\" not unique after argument-dependent lookup in " +
+ type.toString()
));
m_referencedDeclaration = possibleMembers.front().declaration;
@@ -1114,10 +1126,12 @@ void IndexAccess::checkTypeRequirements(TypePointers const*)
if (type.isString())
BOOST_THROW_EXCEPTION(createTypeError("Index access for string is not possible."));
m_index->expectType(IntegerType(256));
- if (type.isByteArray())
- m_type = make_shared<FixedBytesType>(1);
- else
- m_type = type.baseType();
+
+ m_type = type.baseType();
+ if (auto integerType = dynamic_cast<IntegerConstantType const*>(m_index->type().get()))
+ if (!type.isDynamicallySized() && type.length() <= integerType->literalValue(nullptr))
+ BOOST_THROW_EXCEPTION(createTypeError("Out of bounds access."));
+
m_isLValue = type.location() != DataLocation::CallData;
break;
}
@@ -1143,7 +1157,8 @@ void IndexAccess::checkTypeRequirements(TypePointers const*)
if (!length)
BOOST_THROW_EXCEPTION(m_index->createTypeError("Integer constant expected."));
m_type = make_shared<TypeType>(make_shared<ArrayType>(
- DataLocation::Memory, type.actualType(),
+ DataLocation::Memory,
+ type.actualType(),
length->literalValue(nullptr)
));
}
@@ -1151,7 +1166,10 @@ void IndexAccess::checkTypeRequirements(TypePointers const*)
}
default:
BOOST_THROW_EXCEPTION(m_base->createTypeError(
- "Indexed expression has to be a type, mapping or array (is " + m_base->type()->toString() + ")"));
+ "Indexed expression has to be a type, mapping or array (is " +
+ m_base->type()->toString() +
+ ")"
+ ));
}
}
diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp
index b22a78dc..1b9f2150 100644
--- a/libsolidity/ExpressionCompiler.cpp
+++ b/libsolidity/ExpressionCompiler.cpp
@@ -821,6 +821,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
_indexAccess.baseExpression().accept(*this);
Type const& baseType = *_indexAccess.baseExpression().type();
+
if (baseType.category() == Type::Category::Mapping)
{
// stack: storage_base_ref
diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp
index c56845aa..2ba6ab85 100644
--- a/test/libsolidity/SolidityEndToEndTest.cpp
+++ b/test/libsolidity/SolidityEndToEndTest.cpp
@@ -1248,6 +1248,7 @@ BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_fixed_bytes_same_size)
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("bytesToBytes(bytes4)", "abcd") == encodeArgs("abcd"));
}
+
// fixed bytes to uint conversion tests
BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_same_size)
{
@@ -1300,6 +1301,7 @@ BOOST_AUTO_TEST_CASE(convert_fixed_bytes_to_uint_greater_size)
BOOST_CHECK(callContractFunction("bytesToUint(bytes4)", string("abcd")) ==
encodeArgs(u256("0x61626364")));
}
+
// uint fixed bytes conversion tests
BOOST_AUTO_TEST_CASE(convert_uint_to_fixed_bytes_same_size)
{
@@ -4188,7 +4190,8 @@ BOOST_AUTO_TEST_CASE(evm_exceptions_in_constructor_out_of_baund)
uint[3] arr;
function A()
{
- test = arr[5];
+ uint index = 5;
+ test = arr[index];
++test;
}
}
diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp
index 5d174367..2a720494 100644
--- a/test/libsolidity/SolidityNameAndTypeResolution.cpp
+++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp
@@ -2250,10 +2250,23 @@ BOOST_AUTO_TEST_CASE(creating_contract_within_the_contract)
function f() { var x = new Test(); }
}
)";
-
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError);
}
+BOOST_AUTO_TEST_CASE(array_out_of_bound_access)
+{
+ char const* text = R"(
+ contract c {
+ uint[2] dataArray;
+ function set5th() returns (bool) {
+ dataArray[5] = 2;
+ return true;
+ }
+ }
+ )";
+ BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError);
+}
+
BOOST_AUTO_TEST_SUITE_END()
}