mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Clear all mapping knowledge after array variable assignment
This commit is contained in:
parent
6a2809a582
commit
9199718ec0
@ -93,9 +93,10 @@ bool SMTChecker::visit(FunctionDefinition const& _function)
|
|||||||
m_uninterpretedTerms.clear();
|
m_uninterpretedTerms.clear();
|
||||||
resetStateVariables();
|
resetStateVariables();
|
||||||
initializeLocalVariables(_function);
|
initializeLocalVariables(_function);
|
||||||
|
m_loopExecutionHappened = false;
|
||||||
|
m_arrayAssignmentHappened = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_loopExecutionHappened = false;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +273,7 @@ void SMTChecker::endVisit(Assignment const& _assignment)
|
|||||||
}
|
}
|
||||||
else if (dynamic_cast<IndexAccess const*>(&_assignment.leftHandSide()))
|
else if (dynamic_cast<IndexAccess const*>(&_assignment.leftHandSide()))
|
||||||
{
|
{
|
||||||
arrayAssignment(_assignment);
|
arrayIndexAssignment(_assignment);
|
||||||
defineExpr(_assignment, expr(_assignment.rightHandSide()));
|
defineExpr(_assignment, expr(_assignment.rightHandSide()));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -463,6 +464,13 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall)
|
|||||||
m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1));
|
m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SMTChecker::eraseArrayKnowledge()
|
||||||
|
{
|
||||||
|
for (auto const& var: m_variables)
|
||||||
|
if (var.first->annotation().type->category() == Type::Category::Mapping)
|
||||||
|
newValue(*var.first);
|
||||||
|
}
|
||||||
|
|
||||||
void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
|
void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
|
||||||
{
|
{
|
||||||
FunctionDefinition const* _funDef = nullptr;
|
FunctionDefinition const* _funDef = nullptr;
|
||||||
@ -678,7 +686,13 @@ void SMTChecker::endVisit(IndexAccess const& _indexAccess)
|
|||||||
m_uninterpretedTerms.insert(&_indexAccess);
|
m_uninterpretedTerms.insert(&_indexAccess);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SMTChecker::arrayAssignment(Assignment const& _assignment)
|
void SMTChecker::arrayAssignment()
|
||||||
|
{
|
||||||
|
m_arrayAssignmentHappened = true;
|
||||||
|
eraseArrayKnowledge();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SMTChecker::arrayIndexAssignment(Assignment const& _assignment)
|
||||||
{
|
{
|
||||||
auto const& indexAccess = dynamic_cast<IndexAccess const&>(_assignment.leftHandSide());
|
auto const& indexAccess = dynamic_cast<IndexAccess const&>(_assignment.leftHandSide());
|
||||||
if (auto const& id = dynamic_cast<Identifier const*>(&indexAccess.baseExpression()))
|
if (auto const& id = dynamic_cast<Identifier const*>(&indexAccess.baseExpression()))
|
||||||
@ -869,6 +883,8 @@ void SMTChecker::assignment(VariableDeclaration const& _variable, smt::Expressio
|
|||||||
checkUnderOverflow(_value, *intType, _location);
|
checkUnderOverflow(_value, *intType, _location);
|
||||||
else if (dynamic_cast<AddressType const*>(type.get()))
|
else if (dynamic_cast<AddressType const*>(type.get()))
|
||||||
checkUnderOverflow(_value, IntegerType(160), _location);
|
checkUnderOverflow(_value, IntegerType(160), _location);
|
||||||
|
else if (dynamic_cast<MappingType const*>(type.get()))
|
||||||
|
arrayAssignment();
|
||||||
m_interface->addAssertion(newValue(_variable) == _value);
|
m_interface->addAssertion(newValue(_variable) == _value);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,6 +965,12 @@ void SMTChecker::checkCondition(
|
|||||||
loopComment =
|
loopComment =
|
||||||
"\nNote that some information is erased after the execution of loops.\n"
|
"\nNote that some information is erased after the execution of loops.\n"
|
||||||
"You can re-introduce information using require().";
|
"You can re-introduce information using require().";
|
||||||
|
if (m_arrayAssignmentHappened)
|
||||||
|
loopComment +=
|
||||||
|
"\nNote that array aliasing is not supported,"
|
||||||
|
" therefore all mapping information is erased after"
|
||||||
|
" a mapping local variable/parameter is assigned.\n"
|
||||||
|
"You can re-introduce information using require().";
|
||||||
|
|
||||||
switch (result)
|
switch (result)
|
||||||
{
|
{
|
||||||
@ -1082,7 +1104,11 @@ void SMTChecker::initializeFunctionCallParameters(FunctionDefinition const& _fun
|
|||||||
solAssert(funParams.size() == _callArgs.size(), "");
|
solAssert(funParams.size() == _callArgs.size(), "");
|
||||||
for (unsigned i = 0; i < funParams.size(); ++i)
|
for (unsigned i = 0; i < funParams.size(); ++i)
|
||||||
if (createVariable(*funParams[i]))
|
if (createVariable(*funParams[i]))
|
||||||
|
{
|
||||||
m_interface->addAssertion(_callArgs[i] == newValue(*funParams[i]));
|
m_interface->addAssertion(_callArgs[i] == newValue(*funParams[i]));
|
||||||
|
if (funParams[i]->annotation().type->category() == Type::Category::Mapping)
|
||||||
|
m_arrayAssignmentHappened = true;
|
||||||
|
}
|
||||||
|
|
||||||
for (auto const& variable: _function.localVariables())
|
for (auto const& variable: _function.localVariables())
|
||||||
if (createVariable(*variable))
|
if (createVariable(*variable))
|
||||||
|
@ -97,7 +97,14 @@ private:
|
|||||||
|
|
||||||
void defineGlobalVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false);
|
void defineGlobalVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false);
|
||||||
void defineGlobalFunction(std::string const& _name, Expression const& _expr);
|
void defineGlobalFunction(std::string const& _name, Expression const& _expr);
|
||||||
void arrayAssignment(Assignment const& _assignment);
|
/// Handles the side effects of assignment
|
||||||
|
/// to variable of some SMT array type
|
||||||
|
/// while aliasing is not supported.
|
||||||
|
void arrayAssignment();
|
||||||
|
/// Handles assignment to SMT array index.
|
||||||
|
void arrayIndexAssignment(Assignment const& _assignment);
|
||||||
|
/// Erases information about SMT arrays.
|
||||||
|
void eraseArrayKnowledge();
|
||||||
|
|
||||||
/// Division expression in the given type. Requires special treatment because
|
/// Division expression in the given type. Requires special treatment because
|
||||||
/// of rounding for signed division.
|
/// of rounding for signed division.
|
||||||
@ -205,6 +212,7 @@ private:
|
|||||||
std::shared_ptr<smt::SolverInterface> m_interface;
|
std::shared_ptr<smt::SolverInterface> m_interface;
|
||||||
std::shared_ptr<VariableUsage> m_variableUsage;
|
std::shared_ptr<VariableUsage> m_variableUsage;
|
||||||
bool m_loopExecutionHappened = false;
|
bool m_loopExecutionHappened = false;
|
||||||
|
bool m_arrayAssignmentHappened = false;
|
||||||
/// An Expression may have multiple smt::Expression due to
|
/// An Expression may have multiple smt::Expression due to
|
||||||
/// repeated calls to the same function.
|
/// repeated calls to the same function.
|
||||||
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
|
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
|
||||||
|
@ -7,9 +7,12 @@ contract C
|
|||||||
|
|
||||||
function f() public {
|
function f() public {
|
||||||
require(a[1] == b[1]);
|
require(a[1] == b[1]);
|
||||||
|
a[1] = 2;
|
||||||
mapping (uint => uint) storage c = a;
|
mapping (uint => uint) storage c = a;
|
||||||
c[1] = 2;
|
assert(c[1] == 2);
|
||||||
// False negative! Needs aliasing.
|
// False negative! Needs aliasing.
|
||||||
assert(a[1] == b[1]);
|
assert(a[1] == b[1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// ----
|
||||||
|
// Warning: (261-281): Assertion violation happens here
|
||||||
|
Loading…
Reference in New Issue
Block a user