mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #10783 from ethereum/circular-constant-variable
Fix infinite loop when accessing circular constants from inline assem…
This commit is contained in:
commit
de0a3b989d
@ -32,6 +32,7 @@ Bugfixes:
|
||||
* SMTChecker: Fix internal error on pushing string literal to ``bytes`` array.
|
||||
* Type Checker: Fix internal error caused by constant structs containing mappings.
|
||||
* Type System: Disallow implicit conversion from ``uintN`` to ``intM`` when ``M > N``, and by extension, explicit conversion between the same types is also disallowed.
|
||||
* Type Checker: Fix infinite loop when accessing circular constants from inline assembly.
|
||||
* Control Flow Graph: Fix missing error caused by read from/write to uninitialized variables.
|
||||
|
||||
### 0.8.0 (2020-12-16)
|
||||
|
@ -753,6 +753,16 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
|
||||
}
|
||||
if (var->isConstant())
|
||||
{
|
||||
if (isConstantVariableRecursive(*var))
|
||||
{
|
||||
m_errorReporter.typeError(
|
||||
3558_error,
|
||||
_identifier.location,
|
||||
"Constant variable is circular."
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
var = rootConstVariableDeclaration(*var);
|
||||
|
||||
if (var && !var->value())
|
||||
|
@ -19,12 +19,41 @@
|
||||
#include <libsolidity/ast/AST.h>
|
||||
#include <libsolidity/ast/ASTUtils.h>
|
||||
|
||||
#include <libsolutil/Algorithms.h>
|
||||
|
||||
namespace solidity::frontend
|
||||
{
|
||||
|
||||
bool isConstantVariableRecursive(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(_varDecl.isConstant(), "Constant variable expected");
|
||||
|
||||
auto referencedDeclaration = [&](Expression const* _e) -> VariableDeclaration const*
|
||||
{
|
||||
if (auto identifier = dynamic_cast<Identifier const*>(_e))
|
||||
return dynamic_cast<VariableDeclaration const*>(identifier->annotation().referencedDeclaration);
|
||||
else if (auto memberAccess = dynamic_cast<MemberAccess const*>(_e))
|
||||
return dynamic_cast<VariableDeclaration const*>(memberAccess->annotation().referencedDeclaration);
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
auto visitor = [&](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)
|
||||
{
|
||||
solAssert(_depth < 256, "Recursion depth limit reached");
|
||||
|
||||
if (auto referencedVarDecl = referencedDeclaration(_variable.value().get()))
|
||||
if (referencedVarDecl->isConstant())
|
||||
if (_cycleDetector.run(*referencedVarDecl))
|
||||
return;
|
||||
};
|
||||
|
||||
return util::CycleDetector<VariableDeclaration>(visitor).run(_varDecl);
|
||||
}
|
||||
|
||||
VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(_varDecl.isConstant(), "Constant variable expected");
|
||||
solAssert(!isConstantVariableRecursive(_varDecl), "Recursive declaration");
|
||||
|
||||
VariableDeclaration const* rootDecl = &_varDecl;
|
||||
Identifier const* identifier;
|
||||
|
@ -28,4 +28,7 @@ class VariableDeclaration;
|
||||
/// Returns nullptr if an identifier in the chain is not referencing a constant variable declaration.
|
||||
VariableDeclaration const* rootConstVariableDeclaration(VariableDeclaration const& _varDecl);
|
||||
|
||||
/// Returns true if the constant variable declaration is recursive.
|
||||
bool isConstantVariableRecursive(VariableDeclaration const& _varDecl);
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,11 @@
|
||||
contract C {
|
||||
bytes32 constant x = x;
|
||||
function f() public pure returns (uint t) {
|
||||
assembly {
|
||||
// Reference to a circular member
|
||||
t := x
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3558: (171-172): Constant variable is circular.
|
@ -0,0 +1,17 @@
|
||||
==== Source: a ====
|
||||
import "b";
|
||||
uint constant c = d;
|
||||
==== Source: b ====
|
||||
import "a" as M;
|
||||
uint constant b = M.c;
|
||||
uint constant d = b;
|
||||
contract C {
|
||||
uint constant a = b;
|
||||
function f() public returns (uint t) {
|
||||
assembly {
|
||||
t := a
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3558: (b:178-179): Constant variable is circular.
|
@ -0,0 +1,14 @@
|
||||
==== Source: a ====
|
||||
bytes32 constant x = x;
|
||||
==== Source: b ====
|
||||
import "a";
|
||||
contract C {
|
||||
function f() public pure returns (uint t) {
|
||||
assembly {
|
||||
// Reference to a circular member
|
||||
t := x
|
||||
}
|
||||
}
|
||||
}
|
||||
// ----
|
||||
// TypeError 3558: (b:155-156): Constant variable is circular.
|
Loading…
Reference in New Issue
Block a user