Disallow invalid use of library names as type names.

This commit is contained in:
Daniel Kirchner 2020-10-16 17:25:37 +02:00
parent 9aafb62e52
commit 3f14c904b0
13 changed files with 92 additions and 33 deletions

View File

@ -19,6 +19,7 @@ Bugfixes:
* Code generator: Fix internal compiler error when referencing members via module name but not using the reference.
* Code generator: Fix ``ABIEncoderV2`` pragma from the current module affecting inherited functions and applied modifiers.
* Code generator: Use revert instead of invalid opcode for out-of-bounds array index access in getter.
* Type Checker: Disallow invalid use of library names as type name.
* Type Checker: Fix internal compiler error caused by storage parameters with nested mappings in libraries.
* Name Resolver: Fix shadowing/same-name warnings for later declarations.
* Contract Level Checker: Add missing check against inheriting functions with ABIEncoderV2 return types in ABIEncoderV1 contracts.

View File

@ -145,7 +145,11 @@ void DeclarationTypeChecker::endVisit(UserDefinedTypeName const& _typeName)
else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
_typeName.annotation().type = TypeProvider::enumType(*enumDef);
else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
{
if (contract->isLibrary())
m_errorReporter.typeError(1130_error, _typeName.location(), "Invalid use of a library name.");
_typeName.annotation().type = TypeProvider::contract(*contract);
}
else
{
_typeName.annotation().type = TypeProvider::emptyTuple();
@ -201,23 +205,19 @@ void DeclarationTypeChecker::endVisit(Mapping const& _mapping)
return;
if (auto const* typeName = dynamic_cast<UserDefinedTypeName const*>(&_mapping.keyType()))
{
if (auto const* contractType = dynamic_cast<ContractType const*>(typeName->annotation().type))
switch (typeName->annotation().type->category())
{
if (contractType->contractDefinition().isLibrary())
case Type::Category::Enum:
case Type::Category::Contract:
break;
default:
m_errorReporter.fatalTypeError(
1665_error,
7804_error,
typeName->location(),
"Library types cannot be used as mapping keys."
"Only elementary types, contract types or enums are allowed as mapping keys."
);
break;
}
else if (typeName->annotation().type->category() != Type::Category::Enum)
m_errorReporter.fatalTypeError(
7804_error,
typeName->location(),
"Only elementary types, contract types or enums are allowed as mapping keys."
);
}
else
solAssert(dynamic_cast<ElementaryTypeName const*>(&_mapping.keyType()), "");
@ -243,6 +243,7 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
solAssert(!m_errorReporter.errors().empty(), "");
return;
}
solAssert(baseType->storageBytes() != 0, "Illegal base type of storage size zero for array.");
if (Expression const* length = _typeName.length())
{
@ -393,13 +394,36 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
}
void DeclarationTypeChecker::endVisit(UsingForDirective const& _usingFor)
bool DeclarationTypeChecker::visit(UsingForDirective const& _usingFor)
{
ContractDefinition const* library = dynamic_cast<ContractDefinition const*>(
_usingFor.libraryName().annotation().referencedDeclaration
);
if (!library || !library->isLibrary())
m_errorReporter.fatalTypeError(4357_error, _usingFor.libraryName().location(), "Library name expected.");
_usingFor.libraryName().annotation().type = TypeProvider::contract(*library);
if (_usingFor.typeName())
_usingFor.typeName()->accept(*this);
return false;
}
bool DeclarationTypeChecker::visit(InheritanceSpecifier const& _inheritanceSpecifier)
{
auto const* contract = dynamic_cast<ContractDefinition const*>(_inheritanceSpecifier.name().annotation().referencedDeclaration);
solAssert(contract, "");
if (contract->isLibrary())
{
m_errorReporter.typeError(
2571_error,
_inheritanceSpecifier.name().location(),
"Libraries cannot be inherited from."
);
return false;
}
return true;
}
bool DeclarationTypeChecker::check(ASTNode const& _node)

View File

@ -59,7 +59,8 @@ private:
void endVisit(ArrayTypeName const& _typeName) override;
void endVisit(VariableDeclaration const& _variable) override;
bool visit(StructDefinition const& _struct) override;
void endVisit(UsingForDirective const& _usingForDirective) override;
bool visit(UsingForDirective const& _usingForDirective) override;
bool visit(InheritanceSpecifier const& _inheritanceSpecifier) override;
langutil::ErrorReporter& m_errorReporter;
langutil::EVMVersion m_evmVersion;

View File

@ -276,9 +276,6 @@ void TypeChecker::endVisit(InheritanceSpecifier const& _inheritance)
if (m_currentContract->isInterface() && !base->isInterface())
m_errorReporter.typeError(6536_error, _inheritance.location(), "Interfaces can only inherit from other interfaces.");
if (base->isLibrary())
m_errorReporter.typeError(2571_error, _inheritance.location(), "Libraries cannot be inherited from.");
auto const& arguments = _inheritance.arguments();
TypePointers parameterTypes;
if (!base->isInterface())
@ -508,9 +505,6 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
TypePointer varType = _variable.annotation().type;
solAssert(!!varType, "Variable type not provided.");
if (auto contractType = dynamic_cast<ContractType const*>(varType))
if (contractType->contractDefinition().isLibrary())
m_errorReporter.typeError(1273_error, _variable.location(), "The type of a variable cannot be a library.");
if (_variable.value())
{
if (_variable.isStateVariable() && varType->containsNestedMapping())

View File

@ -0,0 +1,8 @@
library L {}
contract C {
function f() public {
L[] memory x;
}
}
// ----
// TypeError 1130: (51-52): Invalid use of a library name.

View File

@ -0,0 +1,8 @@
library L {}
contract C {
function f() public pure {
new L[](2);
}
}
// ----
// TypeError 1130: (63-64): Invalid use of a library name.

View File

@ -0,0 +1,11 @@
library L {}
library M {}
contract C {
using L for M;
using M for L;
using L for L;
}
// ----
// TypeError 1130: (55-56): Invalid use of a library name.
// TypeError 1130: (74-75): Invalid use of a library name.
// TypeError 1130: (93-94): Invalid use of a library name.

View File

@ -0,0 +1,8 @@
library L {}
contract C {
function f() public pure {
new L();
}
}
// ----
// TypeError 1130: (63-64): Invalid use of a library name.

View File

@ -0,0 +1,6 @@
library L {}
contract C {
function f() public override (L) {}
}
// ----
// TypeError 1130: (57-58): Invalid use of a library name.

View File

@ -6,5 +6,4 @@ contract test {
}
}
// ----
// TypeError 1273: (87-90): The type of a variable cannot be a library.
// TypeError 9582: (100-103): Member "l" not found or not visible after argument-dependent lookup in library L.
// TypeError 1130: (87-88): Invalid use of a library name.

View File

@ -1,6 +0,0 @@
library L {}
contract C {
function f() public {
new L();
}
}

View File

@ -9,6 +9,6 @@ contract Y {
}
}
// ----
// TypeError 1273: (29-34): The type of a variable cannot be a library.
// TypeError 1273: (50-57): The type of a variable cannot be a library.
// TypeError 1273: (77-82): The type of a variable cannot be a library.
// TypeError 1130: (29-30): Invalid use of a library name.
// TypeError 1130: (50-51): Invalid use of a library name.
// TypeError 1130: (77-78): Invalid use of a library name.

View File

@ -1,4 +1,9 @@
library L {}
contract C { mapping(L => bool) i; }
contract C
{
mapping(bool => L) j;
mapping(L => bool) i;
}
// ----
// TypeError 1665: (34-35): Library types cannot be used as mapping keys.
// TypeError 1130: (44-45): Invalid use of a library name.
// TypeError 1130: (60-61): Invalid use of a library name.