Merge pull request #2703 from ethereum/warnAboutLargeStorageArrays

Warn about large storage structures.
This commit is contained in:
chriseth
2017-08-14 11:37:01 +02:00
committed by GitHub
4 changed files with 97 additions and 0 deletions
+42
View File
@@ -92,6 +92,17 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
// This is not a no-op, the entry might pre-exist.
m_localVarUseCount[&_variable] += 0;
}
else if (_variable.isStateVariable())
{
set<StructDefinition const*> structsSeen;
if (structureSizeEstimate(*_variable.type(), structsSeen) >= bigint(1) << 64)
m_errorReporter.warning(
_variable.location(),
"Variable covers a large part of storage and thus makes collisions likely. "
"Either use mappings or dynamic arrays and allow their size to be increased only "
"in small quantities per transaction."
);
}
return true;
}
@@ -160,3 +171,34 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
return true;
}
bigint StaticAnalyzer::structureSizeEstimate(Type const& _type, set<StructDefinition const*>& _structsSeen)
{
switch (_type.category())
{
case Type::Category::Array:
{
auto const& t = dynamic_cast<ArrayType const&>(_type);
return structureSizeEstimate(*t.baseType(), _structsSeen) * (t.isDynamicallySized() ? 1 : t.length());
}
case Type::Category::Struct:
{
auto const& t = dynamic_cast<StructType const&>(_type);
bigint size = 1;
if (!_structsSeen.count(&t.structDefinition()))
{
_structsSeen.insert(&t.structDefinition());
for (auto const& m: t.members(nullptr))
size += structureSizeEstimate(*m.type, _structsSeen);
}
return size;
}
case Type::Category::Mapping:
{
return structureSizeEstimate(*dynamic_cast<MappingType const&>(_type).valueType(), _structsSeen);
}
default:
break;
}
return bigint(1);
}
+3
View File
@@ -65,6 +65,9 @@ private:
virtual bool visit(MemberAccess const& _memberAccess) override;
virtual bool visit(InlineAssembly const& _inlineAssembly) override;
/// @returns the size of this type in storage, including all sub-types.
static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
ErrorReporter& m_errorReporter;
/// Flag that indicates whether the current contract definition is a library.