Skip to content

Commit ff5ef45

Browse files
committed
SMTChecker: Loop conditions should be analyzed as in loop context in BMC
Value of loop condition can change between iterations of the loop. Therefore, BMC should be in the "inside loop" state when analyzing loop conditions.
1 parent 27e805d commit ff5ef45

File tree

4 files changed

+27
-6
lines changed

4 files changed

+27
-6
lines changed

Diff for: Changelog.md

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Bugfixes:
1818
* General: Fix internal compiler error when requesting IR AST outputs for interfaces and abstract contracts.
1919
* SMTChecker: Fix internal compiler error when analyzing overflowing expressions or bitwise negation of unsigned types involving constants.
2020
* SMTChecker: Fix reporting on targets that are safe in the context of one contract but unsafe in the context of another contract.
21+
* SMTChecker: Fix SMT logic error in BMC when loop condition is always true in one iteration and always false in the next one.
2122
* SMTChecker: Fix SMT logic error when analyzing cross-contract getter call with BMC.
2223
* SMTChecker: Fix SMT logic error when contract deployment involves string literal to fixed bytes conversion.
2324
* SMTChecker: Fix SMT logic error when external call has extra effectless parentheses.

Diff for: libsolidity/formal/BMC.cpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,9 @@ bool BMC::visit(WhileStatement const& _node)
363363
{
364364
//after loop iterations are done, we check the loop condition last final time
365365
auto indices = copyVariableIndices();
366+
m_loopCheckpoints.emplace();
366367
_node.condition().accept(*this);
368+
m_loopCheckpoints.pop();
367369
loopCondition = expr(_node.condition());
368370
// assert that the loop is complete
369371
m_context.addAssertion(!loopCondition || broke || !loopConditionOnPreviousIterations);
@@ -391,13 +393,13 @@ bool BMC::visit(ForStatement const& _node)
391393
for (unsigned int i = 0; i < bmcLoopIterations; ++i)
392394
{
393395
auto indicesBefore = copyVariableIndices();
396+
m_loopCheckpoints.emplace();
394397
if (_node.condition())
395398
{
396399
_node.condition()->accept(*this);
397400
// values in loop condition might change during loop iteration
398401
forCondition = expr(*_node.condition());
399402
}
400-
m_loopCheckpoints.emplace();
401403
auto indicesAfterCondition = copyVariableIndices();
402404

403405
pushPathCondition(forCondition);
@@ -443,8 +445,10 @@ bool BMC::visit(ForStatement const& _node)
443445
auto indices = copyVariableIndices();
444446
if (_node.condition())
445447
{
448+
m_loopCheckpoints.emplace();
446449
_node.condition()->accept(*this);
447450
forCondition = expr(*_node.condition());
451+
m_loopCheckpoints.pop();
448452
}
449453
// assert that the loop is complete
450454
m_context.addAssertion(!forCondition || broke || !forConditionOnPreviousIterations);
@@ -932,9 +936,9 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
932936
checkAssert(_target);
933937
break;
934938
case VerificationTargetType::ConstantCondition:
935-
solAssert(false, "Checks for constant condition are handled separately");
939+
smtAssert(false, "Checks for constant condition are handled separately");
936940
default:
937-
solAssert(false, "");
941+
smtAssert(false);
938942
}
939943
}
940944

Diff for: libsolidity/formal/BMC.h

+9-3
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,12 @@ class BMC: public SMTEncoder
171171
smtutil::Expression const& _value,
172172
Expression const* _expression
173173
);
174+
/// Special handling of ConstantCondition verification target.
175+
/// The target is checked immediately, unlike the other targets that are queued for checking at the end of analysis.
176+
void checkIfConditionIsConstant(Expression const& _condition);
174177
//@}
175178

176-
void checkIfConditionIsConstant(Expression const& _condition);
179+
177180

178181
/// Solver related.
179182
//@{
@@ -223,20 +226,23 @@ class BMC: public SMTEncoder
223226
/// Number of verification conditions that could not be proved.
224227
size_t m_unprovedAmt = 0;
225228

229+
/// Loop analysis
230+
//@{
226231
enum class LoopControlKind
227232
{
228233
Continue,
229234
Break
230235
};
231236

232-
// Current path conditions and SSA indices for break or continue statement
237+
/// Current path conditions and SSA indices for break or continue statement
233238
struct LoopControl {
234239
LoopControlKind kind;
235240
smtutil::Expression pathConditions;
236241
VariableIndices variableIndices;
237242
};
238243

239-
// Loop control statements for every loop
244+
/// Loop control statements for every loop
240245
std::stack<std::vector<LoopControl>> m_loopCheckpoints;
246+
//@}
241247
};
242248
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
contract Test {
2+
function loop() public pure {
3+
for (uint k = 0; (k == 0 ? true : false); k++) {
4+
}
5+
}
6+
}
7+
// ====
8+
// SMTEngine: bmc
9+
// ----
10+
// Info 6002: BMC: 1 verification condition(s) proved safe! Enable the model checker option "show proved safe" to see all of them.

0 commit comments

Comments
 (0)