mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Fix virtual modifier called statically
This commit is contained in:
parent
67712d50ba
commit
87ef0e16f5
@ -207,12 +207,8 @@ void SMTEncoder::visitFunctionOrModifier()
|
|||||||
auto refDecl = modifierInvocation->name().annotation().referencedDeclaration;
|
auto refDecl = modifierInvocation->name().annotation().referencedDeclaration;
|
||||||
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
if (dynamic_cast<ContractDefinition const*>(refDecl))
|
||||||
visitFunctionOrModifier();
|
visitFunctionOrModifier();
|
||||||
else if (auto modifierDef = dynamic_cast<ModifierDefinition const*>(refDecl))
|
else if (auto modifier = resolveModifierInvocation(*modifierInvocation, m_currentContract))
|
||||||
{
|
inlineModifierInvocation(modifierInvocation.get(), modifier);
|
||||||
solAssert(*modifierInvocation->name().annotation().requiredLookup == VirtualLookup::Virtual, "");
|
|
||||||
ModifierDefinition const& modifier = modifierDef->resolveVirtual(*m_currentContract);
|
|
||||||
inlineModifierInvocation(modifierInvocation.get(), &modifier);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
solAssert(false, "");
|
solAssert(false, "");
|
||||||
}
|
}
|
||||||
@ -2681,23 +2677,34 @@ vector<VariableDeclaration const*> SMTEncoder::modifiersVariables(FunctionDefini
|
|||||||
{
|
{
|
||||||
if (!invok)
|
if (!invok)
|
||||||
continue;
|
continue;
|
||||||
auto decl = invok->name().annotation().referencedDeclaration;
|
auto const* modifier = resolveModifierInvocation(*invok, _contract);
|
||||||
auto const* modifier = dynamic_cast<ModifierDefinition const*>(decl);
|
|
||||||
if (!modifier || visited.count(modifier))
|
if (!modifier || visited.count(modifier))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
visited.insert(modifier);
|
visited.insert(modifier);
|
||||||
solAssert(_contract, "No contract context provided for modifier analysis!");
|
if (modifier->isImplemented())
|
||||||
auto const& actualModifier = modifier->resolveVirtual(*_contract);
|
|
||||||
if (actualModifier.isImplemented())
|
|
||||||
{
|
{
|
||||||
vars += applyMap(actualModifier.parameters(), [](auto _var) { return _var.get(); });
|
vars += applyMap(modifier->parameters(), [](auto _var) { return _var.get(); });
|
||||||
vars += BlockVars(actualModifier.body()).vars;
|
vars += BlockVars(modifier->body()).vars;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return vars;
|
return vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModifierDefinition const* SMTEncoder::resolveModifierInvocation(ModifierInvocation const& _invocation, ContractDefinition const* _contract)
|
||||||
|
{
|
||||||
|
auto const* modifier = dynamic_cast<ModifierDefinition const*>(_invocation.name().annotation().referencedDeclaration);
|
||||||
|
if (modifier)
|
||||||
|
{
|
||||||
|
VirtualLookup lookup = *_invocation.name().annotation().requiredLookup;
|
||||||
|
solAssert(lookup == VirtualLookup::Virtual || lookup == VirtualLookup::Static, "");
|
||||||
|
solAssert(_contract || lookup == VirtualLookup::Static, "No contract context provided for modifier lookup resolution!");
|
||||||
|
if (lookup == VirtualLookup::Virtual)
|
||||||
|
modifier = &modifier->resolveVirtual(*_contract);
|
||||||
|
}
|
||||||
|
return modifier;
|
||||||
|
}
|
||||||
|
|
||||||
SourceUnit const* SMTEncoder::sourceUnitContaining(Scopable const& _scopable)
|
SourceUnit const* SMTEncoder::sourceUnitContaining(Scopable const& _scopable)
|
||||||
{
|
{
|
||||||
for (auto const* s = &_scopable; s; s = dynamic_cast<Scopable const*>(s->scope()))
|
for (auto const* s = &_scopable; s; s = dynamic_cast<Scopable const*>(s->scope()))
|
||||||
|
@ -77,6 +77,9 @@ public:
|
|||||||
static std::vector<VariableDeclaration const*> localVariablesIncludingModifiers(FunctionDefinition const& _function, ContractDefinition const* _contract);
|
static std::vector<VariableDeclaration const*> localVariablesIncludingModifiers(FunctionDefinition const& _function, ContractDefinition const* _contract);
|
||||||
static std::vector<VariableDeclaration const*> modifiersVariables(FunctionDefinition const& _function, ContractDefinition const* _contract);
|
static std::vector<VariableDeclaration const*> modifiersVariables(FunctionDefinition const& _function, ContractDefinition const* _contract);
|
||||||
|
|
||||||
|
/// @returns the ModifierDefinition of a ModifierInvocation if possible, or nullptr.
|
||||||
|
static ModifierDefinition const* resolveModifierInvocation(ModifierInvocation const& _invocation, ContractDefinition const* _contract);
|
||||||
|
|
||||||
/// @returns the SourceUnit that contains _scopable.
|
/// @returns the SourceUnit that contains _scopable.
|
||||||
static SourceUnit const* sourceUnitContaining(Scopable const& _scopable);
|
static SourceUnit const* sourceUnitContaining(Scopable const& _scopable);
|
||||||
|
|
||||||
|
@ -0,0 +1,10 @@
|
|||||||
|
pragma experimental SMTChecker;
|
||||||
|
contract A {
|
||||||
|
modifier m virtual {
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C is A {
|
||||||
|
function f() public A.m returns (uint) {
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,22 @@
|
|||||||
|
pragma experimental SMTChecker;
|
||||||
|
contract A {
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
modifier m virtual {
|
||||||
|
assert(x == 0); // should hold
|
||||||
|
assert(x == 42); // should fail
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
contract C is A {
|
||||||
|
|
||||||
|
modifier m override {
|
||||||
|
assert(x == 1); // This assert is not reachable, should NOT be reported
|
||||||
|
_;
|
||||||
|
}
|
||||||
|
|
||||||
|
function f() public A.m returns (uint) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ----
|
||||||
|
// Warning 6328: (115-130): CHC: Assertion violation happens here.\nCounterexample:\nx = 0\n\n = 0\n\nTransaction trace:\nconstructor()\nState: x = 0\nf()
|
Loading…
Reference in New Issue
Block a user