mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Add warnings for oversized subtypes
This commit is contained in:
parent
c2e1273ff4
commit
1c7a0dcbea
@ -158,7 +158,8 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
|
|||||||
else if (_variable.isStateVariable())
|
else if (_variable.isStateVariable())
|
||||||
{
|
{
|
||||||
set<StructDefinition const*> structsSeen;
|
set<StructDefinition const*> structsSeen;
|
||||||
if (structureSizeEstimate(*_variable.type(), structsSeen) >= bigint(1) << 64)
|
TypeSet oversizedSubTypes;
|
||||||
|
if (structureSizeEstimate(*_variable.type(), structsSeen, oversizedSubTypes) >= bigint(1) << 64)
|
||||||
m_errorReporter.warning(
|
m_errorReporter.warning(
|
||||||
3408_error,
|
3408_error,
|
||||||
_variable.location(),
|
_variable.location(),
|
||||||
@ -166,6 +167,14 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
|
|||||||
"Either use mappings or dynamic arrays and allow their size to be increased only "
|
"Either use mappings or dynamic arrays and allow their size to be increased only "
|
||||||
"in small quantities per transaction."
|
"in small quantities per transaction."
|
||||||
);
|
);
|
||||||
|
for (Type const* type: oversizedSubTypes)
|
||||||
|
m_errorReporter.warning(
|
||||||
|
7325_error,
|
||||||
|
_variable.location(),
|
||||||
|
"Type " + type->canonicalName() + " has large size 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;
|
return true;
|
||||||
}
|
}
|
||||||
@ -339,28 +348,44 @@ bool StaticAnalyzer::visit(FunctionCall const& _functionCall)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bigint StaticAnalyzer::structureSizeEstimate(Type const& _type, set<StructDefinition const*>& _structsSeen)
|
bigint StaticAnalyzer::structureSizeEstimate(
|
||||||
|
Type const& _type,
|
||||||
|
set<StructDefinition const*>& _structsSeen,
|
||||||
|
TypeSet& _oversizedSubTypes
|
||||||
|
)
|
||||||
{
|
{
|
||||||
switch (_type.category())
|
switch (_type.category())
|
||||||
{
|
{
|
||||||
case Type::Category::Array:
|
case Type::Category::Array:
|
||||||
{
|
{
|
||||||
auto const& t = dynamic_cast<ArrayType const&>(_type);
|
auto const& t = dynamic_cast<ArrayType const&>(_type);
|
||||||
|
bigint baseTypeSize = structureSizeEstimate(*t.baseType(), _structsSeen, _oversizedSubTypes);
|
||||||
|
if (baseTypeSize >= bigint(1) << 64)
|
||||||
|
_oversizedSubTypes.insert(t.baseType());
|
||||||
if (!t.isDynamicallySized())
|
if (!t.isDynamicallySized())
|
||||||
return structureSizeEstimate(*t.baseType(), _structsSeen) * t.length();
|
return structureSizeEstimate(*t.baseType(), _structsSeen, _oversizedSubTypes) * t.length();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case Type::Category::Struct:
|
case Type::Category::Struct:
|
||||||
{
|
{
|
||||||
auto const& t = dynamic_cast<StructType const&>(_type);
|
auto const& t = dynamic_cast<StructType const&>(_type);
|
||||||
solAssert(!_structsSeen.count(&t.structDefinition()), "Recursive struct.");
|
|
||||||
bigint size = 1;
|
bigint size = 1;
|
||||||
|
if (_structsSeen.count(&t.structDefinition()))
|
||||||
|
return size;
|
||||||
_structsSeen.insert(&t.structDefinition());
|
_structsSeen.insert(&t.structDefinition());
|
||||||
for (auto const& m: t.members(nullptr))
|
for (auto const& m: t.members(nullptr))
|
||||||
size += structureSizeEstimate(*m.type, _structsSeen);
|
size += structureSizeEstimate(*m.type, _structsSeen, _oversizedSubTypes);
|
||||||
_structsSeen.erase(&t.structDefinition());
|
_structsSeen.erase(&t.structDefinition());
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
case Type::Category::Mapping:
|
||||||
|
{
|
||||||
|
auto const* valueType = dynamic_cast<MappingType const&>(_type).valueType();
|
||||||
|
bigint valueTypeSize = structureSizeEstimate(*valueType, _structsSeen, _oversizedSubTypes);
|
||||||
|
if (valueTypeSize >= bigint(1) << 64)
|
||||||
|
_oversizedSubTypes.insert(valueType);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -73,8 +73,22 @@ private:
|
|||||||
bool visit(BinaryOperation const& _operation) override;
|
bool visit(BinaryOperation const& _operation) override;
|
||||||
bool visit(FunctionCall const& _functionCall) override;
|
bool visit(FunctionCall const& _functionCall) override;
|
||||||
|
|
||||||
|
struct TypeComp
|
||||||
|
{
|
||||||
|
bool operator()(Type const* lhs, Type const* rhs) const
|
||||||
|
{
|
||||||
|
solAssert(lhs && rhs, "");
|
||||||
|
return lhs->richIdentifier() < rhs->richIdentifier();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
using TypeSet = std::set<Type const*, TypeComp>;
|
||||||
|
|
||||||
/// @returns the size of this type in storage, including all sub-types.
|
/// @returns the size of this type in storage, including all sub-types.
|
||||||
static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
|
static bigint structureSizeEstimate(
|
||||||
|
Type const& _type,
|
||||||
|
std::set<StructDefinition const*>& _structsSeen,
|
||||||
|
TypeSet& _oversizedSubTypes
|
||||||
|
);
|
||||||
|
|
||||||
langutil::ErrorReporter& m_errorReporter;
|
langutil::ErrorReporter& m_errorReporter;
|
||||||
|
|
||||||
|
@ -2,3 +2,4 @@ contract C {
|
|||||||
mapping(uint => uint[2**100]) x;
|
mapping(uint => uint[2**100]) x;
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
|
// Warning 7325: (17-48): Type uint256[1267650600228229401496703205376] has large size and thus makes collisions likely. Either use mappings or dynamic arrays and allow their size to be increased only in small quantities per transaction.
|
||||||
|
@ -1,18 +1,65 @@
|
|||||||
contract C {
|
contract C {
|
||||||
struct P0 { uint256[2**63] x; }
|
struct P { uint256[2**63] x; }
|
||||||
|
|
||||||
struct S0 {
|
struct S0 {
|
||||||
P0[2**62] y;
|
P[2**62] x;
|
||||||
P0 x;
|
P y;
|
||||||
}
|
}
|
||||||
S0 s0;
|
S0 s0;
|
||||||
|
|
||||||
struct P1 { uint256[2**63] x; }
|
|
||||||
struct S1 {
|
struct S1 {
|
||||||
P1 x;
|
P x;
|
||||||
P1[2**62] y;
|
P[2**62] y;
|
||||||
}
|
}
|
||||||
S1 s1;
|
S1 s1;
|
||||||
|
|
||||||
|
struct S2 {
|
||||||
|
mapping(uint => P[2**62]) x;
|
||||||
|
mapping(uint => P[2**62]) y;
|
||||||
|
mapping(uint => S2) z;
|
||||||
|
}
|
||||||
|
S2 s2;
|
||||||
|
|
||||||
|
struct Q0
|
||||||
|
{
|
||||||
|
uint[1][][2**65] x;
|
||||||
|
uint[2**65][][1] y;
|
||||||
|
uint[][2**65] z;
|
||||||
|
uint[2**65][] t;
|
||||||
|
}
|
||||||
|
Q0 q0;
|
||||||
|
|
||||||
|
struct Q1
|
||||||
|
{
|
||||||
|
uint[1][][2**65] x;
|
||||||
|
}
|
||||||
|
Q1 q1;
|
||||||
|
|
||||||
|
struct Q2
|
||||||
|
{
|
||||||
|
uint[2**65][][1] y;
|
||||||
|
}
|
||||||
|
Q2 q2;
|
||||||
|
|
||||||
|
struct Q3
|
||||||
|
{
|
||||||
|
uint[][2**65] z;
|
||||||
|
}
|
||||||
|
Q3 q3;
|
||||||
|
|
||||||
|
struct Q4
|
||||||
|
{
|
||||||
|
uint[2**65][] t;
|
||||||
|
}
|
||||||
|
Q4 q4;
|
||||||
}
|
}
|
||||||
// ----
|
// ----
|
||||||
// Warning 3408: (110-115): 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.
|
// Warning 3408: (108-113): 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.
|
||||||
// Warning 3408: (215-220): 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.
|
// Warning 3408: (175-180): 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.
|
||||||
|
// Warning 7325: (314-319): Type C.P[4611686018427387904] has large size and thus makes collisions likely. Either use mappings or dynamic arrays and allow their size to be increased only in small quantities per transaction.
|
||||||
|
// Warning 3408: (458-463): 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.
|
||||||
|
// Warning 7325: (458-463): Type uint256[36893488147419103232] has large size and thus makes collisions likely. Either use mappings or dynamic arrays and allow their size to be increased only in small quantities per transaction.
|
||||||
|
// Warning 3408: (524-529): 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.
|
||||||
|
// Warning 7325: (590-595): Type uint256[36893488147419103232] has large size and thus makes collisions likely. Either use mappings or dynamic arrays and allow their size to be increased only in small quantities per transaction.
|
||||||
|
// Warning 3408: (653-658): 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.
|
||||||
|
// Warning 7325: (716-721): Type uint256[36893488147419103232] has large size and thus makes collisions likely. Either use mappings or dynamic arrays and allow their size to be increased only in small quantities per transaction.
|
||||||
|
Loading…
Reference in New Issue
Block a user