Merge pull request #10836 from ethereum/smt_fix_cex_inheritance

Fix inheritance bug in CHC cex
This commit is contained in:
Leonardo 2021-02-03 18:49:25 +01:00 committed by GitHub
commit 7405dc5b7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 70 additions and 23 deletions

View File

@ -936,9 +936,9 @@ SortPointer CHC::sort(ASTNode const* _node)
return functionBodySort(*m_currentFunction, m_currentContract, state()); return functionBodySort(*m_currentFunction, m_currentContract, state());
} }
Predicate const* CHC::createSymbolicBlock(SortPointer _sort, string const& _name, PredicateType _predType, ASTNode const* _node) Predicate const* CHC::createSymbolicBlock(SortPointer _sort, string const& _name, PredicateType _predType, ASTNode const* _node, ContractDefinition const* _contractContext)
{ {
auto const* block = Predicate::create(_sort, _name, _predType, m_context, _node); auto const* block = Predicate::create(_sort, _name, _predType, m_context, _node, _contractContext);
m_interface->registerRelation(block->functor()); m_interface->registerRelation(block->functor());
return block; return block;
} }
@ -1081,7 +1081,8 @@ Predicate const* CHC::createBlock(ASTNode const* _node, PredicateType _predType,
sort(_node), sort(_node),
"block_" + uniquePrefix() + "_" + _prefix + predicateName(_node), "block_" + uniquePrefix() + "_" + _prefix + predicateName(_node),
_predType, _predType,
_node _node,
m_currentContract
); );
solAssert(m_currentFunction, ""); solAssert(m_currentFunction, "");
@ -1094,7 +1095,8 @@ Predicate const* CHC::createSummaryBlock(FunctionDefinition const& _function, Co
functionSort(_function, &_contract, state()), functionSort(_function, &_contract, state()),
"summary_" + uniquePrefix() + "_" + predicateName(&_function, &_contract), "summary_" + uniquePrefix() + "_" + predicateName(&_function, &_contract),
_type, _type,
&_function &_function,
&_contract
); );
} }
@ -1104,6 +1106,7 @@ Predicate const* CHC::createConstructorBlock(ContractDefinition const& _contract
constructorSort(_contract, state()), constructorSort(_contract, state()),
_prefix + "_" + contractSuffix(_contract) + "_" + uniquePrefix(), _prefix + "_" + contractSuffix(_contract) + "_" + uniquePrefix(),
PredicateType::ConstructorSummary, PredicateType::ConstructorSummary,
&_contract,
&_contract &_contract
); );
} }

View File

@ -126,7 +126,7 @@ private:
/// Predicate helpers. /// Predicate helpers.
//@{ //@{
/// @returns a new block of given _sort and _name. /// @returns a new block of given _sort and _name.
Predicate const* createSymbolicBlock(smtutil::SortPointer _sort, std::string const& _name, PredicateType _predType, ASTNode const* _node = nullptr); Predicate const* createSymbolicBlock(smtutil::SortPointer _sort, std::string const& _name, PredicateType _predType, ASTNode const* _node = nullptr, ContractDefinition const* _contractContext = nullptr);
/// Creates summary predicates for all functions of all contracts /// Creates summary predicates for all functions of all contracts
/// in a given _source. /// in a given _source.

View File

@ -40,7 +40,8 @@ Predicate const* Predicate::create(
string _name, string _name,
PredicateType _type, PredicateType _type,
EncodingContext& _context, EncodingContext& _context,
ASTNode const* _node ASTNode const* _node,
ContractDefinition const* _contractContext
) )
{ {
smt::SymbolicFunctionVariable predicate{_sort, move(_name), _context}; smt::SymbolicFunctionVariable predicate{_sort, move(_name), _context};
@ -49,18 +50,20 @@ Predicate const* Predicate::create(
return &m_predicates.emplace( return &m_predicates.emplace(
std::piecewise_construct, std::piecewise_construct,
std::forward_as_tuple(functorName), std::forward_as_tuple(functorName),
std::forward_as_tuple(move(predicate), _type, _node) std::forward_as_tuple(move(predicate), _type, _node, _contractContext)
).first->second; ).first->second;
} }
Predicate::Predicate( Predicate::Predicate(
smt::SymbolicFunctionVariable&& _predicate, smt::SymbolicFunctionVariable&& _predicate,
PredicateType _type, PredicateType _type,
ASTNode const* _node ASTNode const* _node,
ContractDefinition const* _contractContext
): ):
m_predicate(move(_predicate)), m_predicate(move(_predicate)),
m_type(_type), m_type(_type),
m_node(_node) m_node(_node),
m_contractContext(_contractContext)
{ {
} }
@ -130,18 +133,8 @@ FunctionCall const* Predicate::programFunctionCall() const
optional<vector<VariableDeclaration const*>> Predicate::stateVariables() const optional<vector<VariableDeclaration const*>> Predicate::stateVariables() const
{ {
if (auto const* fun = programFunction()) if (m_contractContext)
return SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*fun); return SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*m_contractContext);
if (auto const* contract = programContract())
return SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*contract);
auto const* node = m_node;
while (auto const* scopable = dynamic_cast<Scopable const*>(node))
{
node = scopable->scope();
if (auto const* fun = dynamic_cast<FunctionDefinition const*>(node))
return SMTEncoder::stateVariablesIncludingInheritedAndPrivate(*fun);
}
return nullopt; return nullopt;
} }

View File

@ -55,13 +55,15 @@ public:
std::string _name, std::string _name,
PredicateType _type, PredicateType _type,
smt::EncodingContext& _context, smt::EncodingContext& _context,
ASTNode const* _node = nullptr ASTNode const* _node = nullptr,
ContractDefinition const* _contractContext = nullptr
); );
Predicate( Predicate(
smt::SymbolicFunctionVariable&& _predicate, smt::SymbolicFunctionVariable&& _predicate,
PredicateType _type, PredicateType _type,
ASTNode const* _node = nullptr ASTNode const* _node = nullptr,
ContractDefinition const* _contractContext = nullptr
); );
/// Predicate should not be copiable. /// Predicate should not be copiable.
@ -166,6 +168,12 @@ private:
/// nullptr if this predicate is not associated with a specific program AST node. /// nullptr if this predicate is not associated with a specific program AST node.
ASTNode const* m_node = nullptr; ASTNode const* m_node = nullptr;
/// The ContractDefinition that contains this predicate.
/// nullptr if this predicate is not associated with a specific contract.
/// This is unfortunately necessary because of virtual resolution for
/// function nodes.
ContractDefinition const* m_contractContext = nullptr;
/// Maps the name of the predicate to the actual Predicate. /// Maps the name of the predicate to the actual Predicate.
/// Used in counterexample generation. /// Used in counterexample generation.
static std::map<std::string, Predicate> m_predicates; static std::map<std::string, Predicate> m_predicates;

View File

@ -0,0 +1,18 @@
pragma experimental SMTChecker;
contract B {
uint x;
function f() public view {
assert(x == 0);
}
}
contract C is B {
uint y;
function g() public {
x = 1;
f();
}
}
// ----
// Warning 6328: (85-99): CHC: Assertion violation happens here.\nCounterexample:\ny = 0, x = 1\n\nTransaction trace:\nC.constructor()\nState: y = 0, x = 0\nC.g()\n B.f() -- internal call\nState: y = 0, x = 1\nB.f()

View File

@ -0,0 +1,25 @@
pragma experimental SMTChecker;
contract A {
uint x;
function f() internal view {
assert(x == 0);
}
}
contract B is A {
uint a;
uint b;
}
contract C is B {
uint y;
uint z;
uint w;
function g() public {
x = 1;
f();
}
}
// ----
// Warning 6328: (87-101): CHC: Assertion violation happens here.\nCounterexample:\ny = 0, z = 0, w = 0, a = 0, b = 0, x = 1\n\nTransaction trace:\nC.constructor()\nState: y = 0, z = 0, w = 0, a = 0, b = 0, x = 0\nC.g()\n A.f() -- internal call