Skip to content

Commit be56477

Browse files
author
Leonardo
authored
Merge pull request #11032 from blishko/smt_string_to_bytes
[SMTChecker] Fix analysis of push to a string casted to bytes
2 parents ad2ecf1 + c5a4581 commit be56477

File tree

5 files changed

+67
-4
lines changed

5 files changed

+67
-4
lines changed

Changelog.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Compiler Features:
77

88

99
Bugfixes:
10-
10+
* SMTChecker: Fix internal error on pushing to ``string`` casted to ``bytes``.
1111

1212
AST Changes:
1313

libsolidity/formal/SMTEncoder.cpp

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1635,7 +1635,7 @@ void SMTEncoder::arrayPop(FunctionCall const& _funCall)
16351635

16361636
void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression const& _array)
16371637
{
1638-
Expression const* expr = innermostTuple(_expr);
1638+
Expression const* expr = cleanExpression(_expr);
16391639

16401640
if (auto const* id = dynamic_cast<Identifier const*>(expr))
16411641
{
@@ -1654,8 +1654,10 @@ void SMTEncoder::arrayPushPopAssign(Expression const& _expr, smtutil::Expression
16541654
indexOrMemberAssignment(_expr, _array);
16551655
else if (auto const* funCall = dynamic_cast<FunctionCall const*>(expr))
16561656
{
1657-
FunctionType const& funType = dynamic_cast<FunctionType const&>(*funCall->expression().annotation().type);
1658-
if (funType.kind() == FunctionType::Kind::ArrayPush)
1657+
if (
1658+
auto funType = dynamic_cast<FunctionType const*>(funCall->expression().annotation().type);
1659+
funType && funType->kind() == FunctionType::Kind::ArrayPush
1660+
)
16591661
{
16601662
auto memberAccess = dynamic_cast<MemberAccess const*>(&funCall->expression());
16611663
solAssert(memberAccess, "");
@@ -2608,6 +2610,33 @@ Expression const* SMTEncoder::innermostTuple(Expression const& _expr)
26082610
return expr;
26092611
}
26102612

2613+
Expression const* SMTEncoder::cleanExpression(Expression const& _expr)
2614+
{
2615+
auto const* expr = &_expr;
2616+
if (auto const* tuple = dynamic_cast<TupleExpression const*>(expr))
2617+
return cleanExpression(*innermostTuple(*tuple));
2618+
if (auto const* functionCall = dynamic_cast<FunctionCall const*>(expr))
2619+
if (*functionCall->annotation().kind == FunctionCallKind::TypeConversion)
2620+
{
2621+
auto typeType = dynamic_cast<TypeType const*>(functionCall->expression().annotation().type);
2622+
solAssert(typeType, "");
2623+
if (auto const* arrayType = dynamic_cast<ArrayType const*>(typeType->actualType()))
2624+
if (arrayType->isByteArray())
2625+
{
2626+
// this is a cast to `bytes`
2627+
solAssert(functionCall->arguments().size() == 1, "");
2628+
Expression const& arg = *functionCall->arguments()[0];
2629+
if (
2630+
auto const* argArrayType = dynamic_cast<ArrayType const*>(arg.annotation().type);
2631+
argArrayType && argArrayType->isByteArray()
2632+
)
2633+
return cleanExpression(arg);
2634+
}
2635+
}
2636+
solAssert(expr, "");
2637+
return expr;
2638+
}
2639+
26112640
set<VariableDeclaration const*> SMTEncoder::touchedVariables(ASTNode const& _node)
26122641
{
26132642
vector<CallableDeclaration const*> callStack;

libsolidity/formal/SMTEncoder.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,12 @@ class SMTEncoder: public ASTConstVisitor
6868
/// otherwise _expr.
6969
static Expression const* innermostTuple(Expression const& _expr);
7070

71+
/// @returns the expression after stripping redundant syntactic sugar.
72+
/// Currently supports stripping:
73+
/// 1. 1-tuple; i.e. ((x)) -> x
74+
/// 2. Explicit cast from string to bytes; i.e. bytes(s) -> s; for s of type string
75+
static Expression const* cleanExpression(Expression const& _expr);
76+
7177
/// @returns the FunctionDefinition of a FunctionCall
7278
/// if possible or nullptr.
7379
/// @param _scopeContract is the contract that contains the function currently being
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pragma experimental SMTChecker;
2+
3+
contract C {
4+
string x;
5+
6+
function s() public {
7+
x = "abc";
8+
bytes(x).push("a");
9+
assert(bytes(x).length == 4); // should hold
10+
assert(bytes(x).length == 3); // should fail
11+
}
12+
}
13+
// ----
14+
// Warning 6328: (165-193): CHC: Assertion violation happens here.\nCounterexample:\nx = [97, 98, 99, 97]\n\nTransaction trace:\nC.constructor()\nState: x = []\nC.s()
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
pragma experimental SMTChecker;
2+
3+
contract C {
4+
string x;
5+
6+
function s() public {
7+
x = "abc";
8+
((bytes(((x))))).push("a");
9+
assert(bytes(x).length == 4); // should hold
10+
assert(bytes(x).length == 3); // should fail
11+
}
12+
}
13+
// ----
14+
// Warning 6328: (173-201): CHC: Assertion violation happens here.\nCounterexample:\nx = [97, 98, 99, 97]\n\nTransaction trace:\nC.constructor()\nState: x = []\nC.s()

0 commit comments

Comments
 (0)