Fix bug in virtual functions called by constructor.

This commit is contained in:
Leonardo Alt
2021-03-12 16:42:28 +01:00
parent ccd9de137a
commit 998346e599
19 changed files with 66 additions and 38 deletions
+17 -17
View File
@@ -139,10 +139,12 @@ bool CHC::visit(ContractDefinition const& _contract)
void CHC::endVisit(ContractDefinition const& _contract)
{
if (auto constructor = _contract.constructor())
constructor->accept(*this);
defineContractInitializer(_contract);
for (auto base: _contract.annotation().linearizedBaseContracts)
{
if (auto constructor = base->constructor())
constructor->accept(*this);
defineContractInitializer(*base, _contract);
}
auto const& entry = *createConstructorBlock(_contract, "implicit_constructor_entry");
@@ -161,7 +163,6 @@ void CHC::endVisit(ContractDefinition const& _contract)
// We need to evaluate the base constructor calls (arguments) from derived -> base
auto baseArgs = baseArguments(_contract);
for (auto base: _contract.annotation().linearizedBaseContracts)
{
if (base != &_contract)
{
m_callGraph[&_contract].insert(base);
@@ -183,13 +184,12 @@ void CHC::endVisit(ContractDefinition const& _contract)
}
}
}
}
m_errorDest = nullptr;
// Then call initializer_Base from base -> derived
for (auto base: _contract.annotation().linearizedBaseContracts | boost::adaptors::reversed)
{
errorFlag().increaseIndex();
m_context.addAssertion(smt::constructorCall(*m_contractInitializers.at(base), m_context));
m_context.addAssertion(smt::constructorCall(*m_contractInitializers.at(&_contract).at(base), m_context));
connectBlocks(m_currentBlock, summary(_contract), errorFlag().currentValue() > 0);
m_context.addAssertion(errorFlag().currentValue() == 0);
}
@@ -953,7 +953,6 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
m_interfaces[contract] = createSymbolicBlock(interfaceSort(*contract, state()), "interface_" + uniquePrefix() + "_" + suffix, PredicateType::Interface, contract);
m_nondetInterfaces[contract] = createSymbolicBlock(nondetInterfaceSort(*contract, state()), "nondet_interface_" + uniquePrefix() + "_" + suffix, PredicateType::NondetInterface, contract);
m_constructorSummaries[contract] = createConstructorBlock(*contract, "summary_constructor");
m_contractInitializers[contract] = createConstructorBlock(*contract, "contract_initializer");
for (auto const* var: stateVariablesIncludingInheritedAndPrivate(*contract))
if (!m_context.knownVariable(*var))
@@ -1001,23 +1000,24 @@ void CHC::defineInterfacesAndSummaries(SourceUnit const& _source)
}
}
void CHC::defineContractInitializer(ContractDefinition const& _contract)
void CHC::defineContractInitializer(ContractDefinition const& _contract, ContractDefinition const& _contextContract)
{
m_contractInitializers[&_contextContract][&_contract] = createConstructorBlock(_contract, "contract_initializer");
auto const& implicitConstructorPredicate = *createConstructorBlock(_contract, "contract_initializer_entry");
auto implicitFact = smt::constructor(implicitConstructorPredicate, m_context);
addRule(smtutil::Expression::implies(initialConstraints(_contract), implicitFact), implicitFact.name);
setCurrentBlock(implicitConstructorPredicate);
solAssert(!m_errorDest, "");
m_errorDest = m_contractInitializers.at(&_contract);
auto prevErrorDest = m_errorDest;
m_errorDest = m_contractInitializers.at(&_contextContract).at(&_contract);
for (auto var: _contract.stateVariables())
if (var->value())
{
var->value()->accept(*this);
assignment(*var, *var->value());
}
m_errorDest = nullptr;
m_errorDest = prevErrorDest;
auto const& afterInit = *createConstructorBlock(_contract, "contract_initializer_after_init");
connectBlocks(m_currentBlock, predicate(afterInit));
@@ -1026,12 +1026,12 @@ void CHC::defineContractInitializer(ContractDefinition const& _contract)
if (auto constructor = _contract.constructor())
{
errorFlag().increaseIndex();
m_context.addAssertion(smt::functionCall(*m_summaries.at(&_contract).at(constructor), &_contract, m_context));
connectBlocks(m_currentBlock, initializer(_contract), errorFlag().currentValue() > 0);
m_context.addAssertion(smt::functionCall(*m_summaries.at(&_contextContract).at(constructor), &_contextContract, m_context));
connectBlocks(m_currentBlock, initializer(_contract, _contextContract), errorFlag().currentValue() > 0);
m_context.addAssertion(errorFlag().currentValue() == 0);
}
connectBlocks(m_currentBlock, initializer(_contract));
connectBlocks(m_currentBlock, initializer(_contract, _contextContract));
}
smtutil::Expression CHC::interface()
@@ -1055,9 +1055,9 @@ smtutil::Expression CHC::error(unsigned _idx)
return m_errorPredicate->functor(_idx)({});
}
smtutil::Expression CHC::initializer(ContractDefinition const& _contract)
smtutil::Expression CHC::initializer(ContractDefinition const& _contract, ContractDefinition const& _contractContext)
{
return predicate(*m_contractInitializers.at(&_contract));
return predicate(*m_contractInitializers.at(&_contractContext).at(&_contract));
}
smtutil::Expression CHC::summary(ContractDefinition const& _contract)
+4 -4
View File
@@ -135,7 +135,7 @@ private:
/// Creates a CHC system that, for a given contract,
/// - initializes its state variables (as 0 or given value, if any).
/// - "calls" the explicit constructor function of the contract, if any.
void defineContractInitializer(ContractDefinition const& _contract);
void defineContractInitializer(ContractDefinition const& _contract, ContractDefinition const& _contractContext);
/// Interface predicate over current variables.
smtutil::Expression interface();
@@ -183,8 +183,8 @@ private:
smtutil::Expression predicate(Predicate const& _block);
/// @returns the summary predicate for the called function.
smtutil::Expression predicate(FunctionCall const& _funCall);
/// @returns a predicate that defines a contract initializer.
smtutil::Expression initializer(ContractDefinition const& _contract);
/// @returns a predicate that defines a contract initializer for _contract in the context of _contractContext.
smtutil::Expression initializer(ContractDefinition const& _contract, ContractDefinition const& _contractContext);
/// @returns a predicate that defines a constructor summary.
smtutil::Expression summary(ContractDefinition const& _contract);
/// @returns a predicate that defines a function summary.
@@ -274,7 +274,7 @@ private:
std::map<ContractDefinition const*, Predicate const*> m_nondetInterfaces;
std::map<ContractDefinition const*, Predicate const*> m_constructorSummaries;
std::map<ContractDefinition const*, Predicate const*> m_contractInitializers;
std::map<ContractDefinition const*, std::map<ContractDefinition const*, Predicate const*>> m_contractInitializers;
/// Artificial Error predicate.
/// Single error block for all assertions.
+1 -2
View File
@@ -2904,8 +2904,7 @@ set<FunctionDefinition const*, ASTNode::CompareByID> const& SMTEncoder::contract
auto allFunctions = contractFunctions(_contract);
for (auto const* base: _contract.annotation().linearizedBaseContracts)
for (auto const* baseFun: base->definedFunctions())
if (!baseFun->isConstructor())
allFunctions.insert(baseFun);
allFunctions.insert(baseFun);
m_contractFunctionsWithoutVirtual.emplace(&_contract, move(allFunctions));