[SMTChecker] Support user types

This commit is contained in:
Leo Alt
2021-09-21 13:23:17 +02:00
parent 659498ff50
commit e74f853c6b
23 changed files with 462 additions and 14 deletions
+2
View File
@@ -483,6 +483,8 @@ void BMC::endVisit(FunctionCall const& _funCall)
case FunctionType::Kind::BlockHash:
case FunctionType::Kind::AddMod:
case FunctionType::Kind::MulMod:
case FunctionType::Kind::Unwrap:
case FunctionType::Kind::Wrap:
[[fallthrough]];
default:
SMTEncoder::endVisit(_funCall);
+2
View File
@@ -553,6 +553,8 @@ void CHC::endVisit(FunctionCall const& _funCall)
case FunctionType::Kind::BlockHash:
case FunctionType::Kind::AddMod:
case FunctionType::Kind::MulMod:
case FunctionType::Kind::Unwrap:
case FunctionType::Kind::Wrap:
[[fallthrough]];
default:
SMTEncoder::endVisit(_funCall);
+3 -3
View File
@@ -237,7 +237,7 @@ string Predicate::formatSummaryCall(
auto last = first + static_cast<int>(fun->parameters().size());
solAssert(first >= _args.begin() && first <= _args.end(), "");
solAssert(last >= _args.begin() && last <= _args.end(), "");
auto inTypes = FunctionType(*fun).parameterTypes();
auto inTypes = SMTEncoder::replaceUserTypes(FunctionType(*fun).parameterTypes());
vector<optional<string>> functionArgsCex = formatExpressions(vector<smtutil::Expression>(first, last), inTypes);
vector<string> functionArgs;
@@ -317,7 +317,7 @@ vector<optional<string>> Predicate::summaryPostInputValues(vector<smtutil::Expre
vector<smtutil::Expression> inValues(first, last);
solAssert(inValues.size() == inParams.size(), "");
auto inTypes = FunctionType(*function).parameterTypes();
auto inTypes = SMTEncoder::replaceUserTypes(FunctionType(*function).parameterTypes());
return formatExpressions(inValues, inTypes);
}
@@ -339,7 +339,7 @@ vector<optional<string>> Predicate::summaryPostOutputValues(vector<smtutil::Expr
vector<smtutil::Expression> outValues(first, _args.end());
solAssert(outValues.size() == function->returnParameters().size(), "");
auto outTypes = FunctionType(*function).returnParameterTypes();
auto outTypes = SMTEncoder::replaceUserTypes(FunctionType(*function).returnParameterTypes());
return formatExpressions(outValues, outTypes);
}
+59 -9
View File
@@ -370,7 +370,7 @@ void SMTEncoder::endVisit(Assignment const& _assignment)
Token op = _assignment.assignmentOperator();
solAssert(TokenTraits::isAssignmentOp(op), "");
if (!smt::isSupportedType(*_assignment.annotation().type))
if (!isSupportedType(*_assignment.annotation().type))
{
// Give it a new index anyway to keep the SSA scheme sound.
@@ -406,6 +406,9 @@ void SMTEncoder::endVisit(TupleExpression const& _tuple)
if (_tuple.annotation().type->category() == Type::Category::Function)
return;
if (_tuple.annotation().type->category() == Type::Category::TypeType)
return;
createExpr(_tuple);
if (_tuple.isInlineArray())
@@ -575,6 +578,17 @@ bool SMTEncoder::visit(FunctionCall const& _funCall)
arg->accept(*this);
return false;
}
// We do not really need to visit the expression in a wrap/unwrap no-op call,
// so we just ignore the function call expression to avoid "unsupported" warnings.
else if (
funType.kind() == FunctionType::Kind::Wrap ||
funType.kind() == FunctionType::Kind::Unwrap
)
{
if (auto arg = _funCall.arguments().front())
arg->accept(*this);
return false;
}
return true;
}
@@ -641,6 +655,10 @@ void SMTEncoder::endVisit(FunctionCall const& _funCall)
case FunctionType::Kind::MulMod:
visitAddMulMod(_funCall);
break;
case FunctionType::Kind::Unwrap:
case FunctionType::Kind::Wrap:
visitWrapUnwrap(_funCall);
break;
case FunctionType::Kind::Send:
case FunctionType::Kind::Transfer:
{
@@ -846,6 +864,13 @@ void SMTEncoder::visitAddMulMod(FunctionCall const& _funCall)
defineExpr(_funCall, divModWithSlacks(x * y, k, intType).second);
}
void SMTEncoder::visitWrapUnwrap(FunctionCall const& _funCall)
{
auto const& args = _funCall.arguments();
solAssert(args.size() == 1, "");
defineExpr(_funCall, expr(*args.front()));
}
void SMTEncoder::visitObjectCreation(FunctionCall const& _funCall)
{
auto const& args = _funCall.arguments();
@@ -889,6 +914,9 @@ void SMTEncoder::endVisit(Identifier const& _identifier)
// Ignore module identifiers
else if (dynamic_cast<ModuleType const*>(_identifier.annotation().type))
return;
// Ignore user defined value type identifiers
else if (dynamic_cast<UserDefinedValueType const*>(_identifier.annotation().type))
return;
// Ignore the builtin abi, it is handled in FunctionCall.
// TODO: ignore MagicType in general (abi, block, msg, tx, type)
else if (auto magicType = dynamic_cast<MagicType const*>(_identifier.annotation().type); magicType && magicType->kind() == MagicType::Kind::ABI)
@@ -944,7 +972,7 @@ void SMTEncoder::visitPublicGetter(FunctionCall const& _funCall)
auto var = dynamic_cast<VariableDeclaration const*>(access.annotation().referencedDeclaration);
solAssert(var, "");
solAssert(m_context.knownExpression(_funCall), "");
auto paramExpectedTypes = FunctionType(*var).parameterTypes();
auto paramExpectedTypes = replaceUserTypes(FunctionType(*var).parameterTypes());
auto actualArguments = _funCall.arguments();
solAssert(actualArguments.size() == paramExpectedTypes.size(), "");
deque<smtutil::Expression> symbArguments;
@@ -1164,7 +1192,7 @@ void SMTEncoder::visitTypeConversion(FunctionCall const& _funCall)
void SMTEncoder::visitFunctionIdentifier(Identifier const& _identifier)
{
auto const& fType = dynamic_cast<FunctionType const&>(*_identifier.annotation().type);
if (fType.returnParameterTypes().size() == 1)
if (replaceUserTypes(fType.returnParameterTypes()).size() == 1)
{
defineGlobalVariable(fType.identifier(), _identifier);
m_context.createExpression(_identifier, m_context.globalSymbol(fType.identifier()));
@@ -1647,7 +1675,7 @@ void SMTEncoder::defineGlobalVariable(string const& _name, Expression const& _ex
m_context.globalSymbol(_name)->increaseIndex();
// The default behavior is not to increase the index since
// most of the global values stay the same throughout a tx.
if (smt::isSupportedType(*_expr.annotation().type))
if (isSupportedType(*_expr.annotation().type))
defineExpr(_expr, m_context.globalSymbol(_name)->currentValue());
}
@@ -1843,9 +1871,10 @@ smtutil::Expression SMTEncoder::bitwiseOperation(
void SMTEncoder::compareOperation(BinaryOperation const& _op)
{
auto const& commonType = _op.annotation().commonType;
auto commonType = _op.annotation().commonType;
solAssert(commonType, "");
if (smt::isSupportedType(*commonType))
if (isSupportedType(*commonType))
{
smtutil::Expression left(expr(_op.leftExpression(), commonType));
smtutil::Expression right(expr(_op.rightExpression(), commonType));
@@ -1978,7 +2007,7 @@ void SMTEncoder::assignment(
Expression const* left = cleanExpression(_left);
if (!smt::isSupportedType(*_type))
if (!isSupportedType(*_type))
{
// Give it a new index anyway to keep the SSA scheme sound.
if (auto varDecl = identifierToVariable(*left))
@@ -2019,7 +2048,7 @@ void SMTEncoder::assignment(
}
else if (funType->kind() == FunctionType::Kind::Internal)
{
for (auto type: funType->returnParameterTypes())
for (auto type: replaceUserTypes(funType->returnParameterTypes()))
if (type->category() == Type::Category::Mapping || dynamic_cast<ReferenceType const*>(type))
resetReferences(type);
}
@@ -2356,6 +2385,11 @@ bool SMTEncoder::sameTypeOrSubtype(Type const* _a, Type const* _b)
return false;
}
bool SMTEncoder::isSupportedType(Type const& _type) const
{
return smt::isSupportedType(*underlyingType(&_type));
}
Type const* SMTEncoder::typeWithoutPointer(Type const* _type)
{
if (auto refType = dynamic_cast<ReferenceType const*>(_type))
@@ -2417,7 +2451,7 @@ smtutil::Expression SMTEncoder::expr(Expression const& _e, Type const* _targetTy
createExpr(_e);
}
return m_context.expression(_e)->currentValue(_targetType);
return m_context.expression(_e)->currentValue(underlyingType(_targetType));
}
void SMTEncoder::createExpr(Expression const& _e)
@@ -2608,6 +2642,22 @@ Expression const* SMTEncoder::innermostTuple(Expression const& _expr)
return expr;
}
Type const* SMTEncoder::underlyingType(Type const* _type)
{
if (auto userType = dynamic_cast<UserDefinedValueType const*>(_type))
_type = &userType->underlyingType();
return _type;
}
TypePointers SMTEncoder::replaceUserTypes(TypePointers const& _types)
{
return applyMap(_types, [](auto _type) {
if (auto userType = dynamic_cast<UserDefinedValueType const*>(_type))
return &userType->underlyingType();
return _type;
});
}
pair<Expression const*, FunctionCallOptions const*> SMTEncoder::functionCallExpression(FunctionCall const& _funCall)
{
Expression const* callExpr = &_funCall.expression();
+9
View File
@@ -71,6 +71,12 @@ public:
/// otherwise _expr.
static Expression const* innermostTuple(Expression const& _expr);
/// @returns the underlying type if _type is UserDefinedValueType,
/// and _type otherwise.
static Type const* underlyingType(Type const* _type);
static TypePointers replaceUserTypes(TypePointers const& _types);
/// @returns {_funCall.expression(), nullptr} if function call option values are not given, and
/// {_funCall.expression().expression(), _funCall.expression()} if they are.
static std::pair<Expression const*, FunctionCallOptions const*> functionCallExpression(FunctionCall const& _funCall);
@@ -207,6 +213,7 @@ protected:
void visitCryptoFunction(FunctionCall const& _funCall);
void visitGasLeft(FunctionCall const& _funCall);
virtual void visitAddMulMod(FunctionCall const& _funCall);
void visitWrapUnwrap(FunctionCall const& _funCall);
void visitObjectCreation(FunctionCall const& _funCall);
void visitTypeConversion(FunctionCall const& _funCall);
void visitStructConstructorCall(FunctionCall const& _funCall);
@@ -319,6 +326,8 @@ protected:
/// @returns whether _a or a subtype of _a is the same as _b.
bool sameTypeOrSubtype(Type const* _a, Type const* _b);
bool isSupportedType(Type const& _type) const;
/// Given the state of the symbolic variables at the end of two different branches,
/// create a merged state using the given branch condition.
void mergeVariables(smtutil::Expression const& _condition, VariableIndices const& _indicesEndTrue, VariableIndices const& _indicesEndFalse);
+2
View File
@@ -270,6 +270,8 @@ void SymbolicState::buildABIFunctions(set<FunctionCall const*> const& _abiFuncti
t = TypeProvider::uint256();
else if (t->category() == frontend::Type::Category::StringLiteral)
t = TypeProvider::bytesMemory();
else if (auto userType = dynamic_cast<UserDefinedValueType const*>(t))
t = &userType->underlyingType();
};
replaceTypes(inTypes);
replaceTypes(outTypes);
+4
View File
@@ -233,6 +233,10 @@ pair<bool, shared_ptr<SymbolicVariable>> newSymbolicVariable(
bool abstract = false;
shared_ptr<SymbolicVariable> var;
frontend::Type const* type = &_type;
if (auto userType = dynamic_cast<UserDefinedValueType const*>(type))
return newSymbolicVariable(userType->underlyingType(), _uniqueName, _context);
if (!isSupportedTypeDeclaration(_type))
{
abstract = true;