mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[SMTChecker] Support array length
This commit is contained in:
@@ -890,6 +890,33 @@ bool SMTEncoder::visit(MemberAccess const& _memberAccess)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (exprType->category() == Type::Category::Array)
|
||||
{
|
||||
_memberAccess.expression().accept(*this);
|
||||
if (_memberAccess.memberName() == "length")
|
||||
{
|
||||
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(_memberAccess.expression()));
|
||||
solAssert(symbArray, "");
|
||||
defineExpr(_memberAccess, symbArray->length());
|
||||
m_uninterpretedTerms.insert(&_memberAccess);
|
||||
setSymbolicUnknownValue(
|
||||
expr(_memberAccess),
|
||||
_memberAccess.annotation().type,
|
||||
m_context
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const& name = _memberAccess.memberName();
|
||||
solAssert(name == "push" || name == "pop", "");
|
||||
m_errorReporter.warning(
|
||||
9098_error,
|
||||
_memberAccess.location(),
|
||||
"Assertion checker does not yet support array member \"" + name + "\"."
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
else
|
||||
m_errorReporter.warning(
|
||||
7650_error,
|
||||
@@ -939,9 +966,10 @@ void SMTEncoder::endVisit(IndexAccess const& _indexAccess)
|
||||
return;
|
||||
}
|
||||
|
||||
solAssert(array, "");
|
||||
auto arrayVar = dynamic_pointer_cast<smt::SymbolicArrayVariable>(array);
|
||||
solAssert(arrayVar, "");
|
||||
defineExpr(_indexAccess, smt::Expression::select(
|
||||
array->currentValue(),
|
||||
arrayVar->elements(),
|
||||
expr(*_indexAccess.indexExpression())
|
||||
));
|
||||
setSymbolicUnknownValue(
|
||||
@@ -1013,16 +1041,20 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smt::Expression c
|
||||
return false;
|
||||
});
|
||||
|
||||
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.variable(*varDecl));
|
||||
smt::Expression store = smt::Expression::store(
|
||||
m_context.variable(*varDecl)->currentValue(),
|
||||
symbArray->elements(),
|
||||
expr(*indexAccess->indexExpression()),
|
||||
toStore
|
||||
);
|
||||
m_context.addAssertion(m_context.newValue(*varDecl) == store);
|
||||
auto oldLength = symbArray->length();
|
||||
symbArray->increaseIndex();
|
||||
m_context.addAssertion(symbArray->elements() == store);
|
||||
m_context.addAssertion(symbArray->length() == oldLength);
|
||||
// Update the SMT select value after the assignment,
|
||||
// necessary for sound models.
|
||||
defineExpr(*indexAccess, smt::Expression::select(
|
||||
m_context.variable(*varDecl)->currentValue(),
|
||||
symbArray->elements(),
|
||||
expr(*indexAccess->indexExpression())
|
||||
));
|
||||
|
||||
@@ -1030,7 +1062,12 @@ void SMTEncoder::arrayIndexAssignment(Expression const& _expr, smt::Expression c
|
||||
}
|
||||
else if (auto base = dynamic_cast<IndexAccess const*>(&indexAccess->baseExpression()))
|
||||
{
|
||||
toStore = smt::Expression::store(expr(*base), expr(*indexAccess->indexExpression()), toStore);
|
||||
auto symbArray = dynamic_pointer_cast<smt::SymbolicArrayVariable>(m_context.expression(*base));
|
||||
solAssert(symbArray, "");
|
||||
toStore = smt::Expression::tuple_constructor(
|
||||
smt::Expression(base->annotation().type),
|
||||
{smt::Expression::store(symbArray->elements(), expr(*indexAccess->indexExpression()), toStore), symbArray->length()}
|
||||
);
|
||||
indexAccess = base;
|
||||
}
|
||||
else
|
||||
@@ -1326,7 +1363,14 @@ smt::Expression SMTEncoder::compoundAssignment(Assignment const& _assignment)
|
||||
|
||||
void SMTEncoder::assignment(VariableDeclaration const& _variable, Expression const& _value)
|
||||
{
|
||||
assignment(_variable, expr(_value, _variable.type()));
|
||||
// In general, at this point, the SMT sorts of _variable and _value are the same,
|
||||
// even if there is implicit conversion.
|
||||
// This is a special case where the SMT sorts are different.
|
||||
// For now we are unaware of other cases where this happens, but if they do appear
|
||||
// we should extract this into an `implicitConversion` function.
|
||||
if (_variable.type()->category() != Type::Category::Array || _value.annotation().type->category() != Type::Category::StringLiteral)
|
||||
assignment(_variable, expr(_value, _variable.type()));
|
||||
// TODO else { store each string literal byte into the array }
|
||||
}
|
||||
|
||||
void SMTEncoder::assignment(VariableDeclaration const& _variable, smt::Expression const& _value)
|
||||
@@ -1616,7 +1660,7 @@ SMTEncoder::VariableIndices SMTEncoder::copyVariableIndices()
|
||||
void SMTEncoder::resetVariableIndices(VariableIndices const& _indices)
|
||||
{
|
||||
for (auto const& var: _indices)
|
||||
m_context.variable(*var.first)->index() = var.second;
|
||||
m_context.variable(*var.first)->setIndex(var.second);
|
||||
}
|
||||
|
||||
void SMTEncoder::clearIndices(ContractDefinition const* _contract, FunctionDefinition const* _function)
|
||||
|
||||
Reference in New Issue
Block a user