diff options
author | chriseth <chris@ethereum.org> | 2017-08-07 21:44:35 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2017-08-12 02:57:57 +0800 |
commit | da3ac8640328c15872630d5d86976f17480f9492 (patch) | |
tree | 8e2134191c50dd31657b3c78b1d4bc7166ae4a11 /libsolidity | |
parent | d968912a4ce89a40d7d03bf0748a07c397662f68 (diff) | |
download | dexon-solidity-da3ac8640328c15872630d5d86976f17480f9492.tar.gz dexon-solidity-da3ac8640328c15872630d5d86976f17480f9492.tar.zst dexon-solidity-da3ac8640328c15872630d5d86976f17480f9492.zip |
Warn about large storage structures.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/StaticAnalyzer.cpp | 42 | ||||
-rw-r--r-- | libsolidity/analysis/StaticAnalyzer.h | 3 |
2 files changed, 45 insertions, 0 deletions
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp index 46477e1e..ab1cbb52 100644 --- a/libsolidity/analysis/StaticAnalyzer.cpp +++ b/libsolidity/analysis/StaticAnalyzer.cpp @@ -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); +} diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h index 21a487df..a3080b42 100644 --- a/libsolidity/analysis/StaticAnalyzer.h +++ b/libsolidity/analysis/StaticAnalyzer.h @@ -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. |