@@ -247,14 +247,8 @@ bool BMC::visit(IfStatement const& _node)
247
247
m_context.pushSolver ();
248
248
_node.condition ().accept (*this );
249
249
250
- // We ignore called functions here because they have
251
- // specific input values.
252
- if (isRootFunction () && !isInsideLoop ())
253
- addVerificationTarget (
254
- VerificationTargetType::ConstantCondition,
255
- expr (_node.condition ()),
256
- &_node.condition ()
257
- );
250
+ checkIfConditionIsConstant (_node.condition ());
251
+
258
252
m_context.popSolver ();
259
253
resetVariableIndices (std::move (indicesBeforePush));
260
254
@@ -283,13 +277,7 @@ bool BMC::visit(Conditional const& _op)
283
277
auto indicesBeforePush = copyVariableIndices ();
284
278
m_context.pushSolver ();
285
279
_op.condition ().accept (*this );
286
-
287
- if (isRootFunction () && !isInsideLoop ())
288
- addVerificationTarget (
289
- VerificationTargetType::ConstantCondition,
290
- expr (_op.condition ()),
291
- &_op.condition ()
292
- );
280
+ checkIfConditionIsConstant (_op.condition ());
293
281
m_context.popSolver ();
294
282
resetVariableIndices (std::move (indicesBeforePush));
295
283
@@ -375,7 +363,9 @@ bool BMC::visit(WhileStatement const& _node)
375
363
{
376
364
// after loop iterations are done, we check the loop condition last final time
377
365
auto indices = copyVariableIndices ();
366
+ m_loopCheckpoints.emplace ();
378
367
_node.condition ().accept (*this );
368
+ m_loopCheckpoints.pop ();
379
369
loopCondition = expr (_node.condition ());
380
370
// assert that the loop is complete
381
371
m_context.addAssertion (!loopCondition || broke || !loopConditionOnPreviousIterations);
@@ -403,13 +393,13 @@ bool BMC::visit(ForStatement const& _node)
403
393
for (unsigned int i = 0 ; i < bmcLoopIterations; ++i)
404
394
{
405
395
auto indicesBefore = copyVariableIndices ();
396
+ m_loopCheckpoints.emplace ();
406
397
if (_node.condition ())
407
398
{
408
399
_node.condition ()->accept (*this );
409
400
// values in loop condition might change during loop iteration
410
401
forCondition = expr (*_node.condition ());
411
402
}
412
- m_loopCheckpoints.emplace ();
413
403
auto indicesAfterCondition = copyVariableIndices ();
414
404
415
405
pushPathCondition (forCondition);
@@ -455,8 +445,10 @@ bool BMC::visit(ForStatement const& _node)
455
445
auto indices = copyVariableIndices ();
456
446
if (_node.condition ())
457
447
{
448
+ m_loopCheckpoints.emplace ();
458
449
_node.condition ()->accept (*this );
459
450
forCondition = expr (*_node.condition ());
451
+ m_loopCheckpoints.pop ();
460
452
}
461
453
// assert that the loop is complete
462
454
m_context.addAssertion (!forCondition || broke || !forConditionOnPreviousIterations);
@@ -690,12 +682,7 @@ void BMC::visitRequire(FunctionCall const& _funCall)
690
682
auto const & args = _funCall.arguments ();
691
683
solAssert (args.size () >= 1 , " " );
692
684
solAssert (args.front ()->annotation ().type ->category () == Type::Category::Bool, " " );
693
- if (isRootFunction () && !isInsideLoop ())
694
- addVerificationTarget (
695
- VerificationTargetType::ConstantCondition,
696
- expr (*args.front ()),
697
- args.front ().get ()
698
- );
685
+ checkIfConditionIsConstant (*args.front ());
699
686
}
700
687
701
688
void BMC::visitAddMulMod (FunctionCall const & _funCall)
@@ -933,9 +920,6 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
933
920
934
921
switch (_target.type )
935
922
{
936
- case VerificationTargetType::ConstantCondition:
937
- checkConstantCondition (_target);
938
- break ;
939
923
case VerificationTargetType::Underflow:
940
924
checkUnderflow (_target);
941
925
break ;
@@ -951,19 +935,70 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
951
935
case VerificationTargetType::Assert:
952
936
checkAssert (_target);
953
937
break ;
938
+ case VerificationTargetType::ConstantCondition:
939
+ smtAssert (false , " Checks for constant condition are handled separately" );
954
940
default :
955
- solAssert (false , " " );
941
+ smtAssert (false );
956
942
}
957
943
}
958
944
959
- void BMC::checkConstantCondition (BMCVerificationTarget& _target )
945
+ void BMC::checkIfConditionIsConstant (Expression const & _condition )
960
946
{
961
- checkBooleanNotConstant (
962
- *_target.expression ,
963
- _target.constraints ,
964
- _target.value ,
965
- _target.callStack
966
- );
947
+ if (
948
+ !m_settings.targets .has (VerificationTargetType::ConstantCondition) ||
949
+ (m_currentContract && !shouldEncode (*m_currentContract))
950
+ )
951
+ return ;
952
+
953
+ // We ignore called functions here because they have specific input values.
954
+ // Also, expressions inside loop can have different values in different iterations.
955
+ if (!isRootFunction () || isInsideLoop ())
956
+ return ;
957
+
958
+ // Do not check for const-ness if this is a literal.
959
+ if (dynamic_cast <Literal const *>(&_condition))
960
+ return ;
961
+
962
+ auto [canBeTrue, canBeFalse] = checkBooleanNotConstant (currentPathConditions () && m_context.assertions (), expr (_condition));
963
+
964
+ // Report based on the result of the checks
965
+ if (canBeTrue == CheckResult::ERROR || canBeFalse == CheckResult::ERROR)
966
+ m_errorReporter.warning (8592_error, _condition.location (), " BMC: Error trying to invoke SMT solver." );
967
+ else if (canBeTrue == CheckResult::CONFLICTING || canBeFalse == CheckResult::CONFLICTING)
968
+ m_errorReporter.warning (3356_error, _condition.location (), " BMC: At least two SMT solvers provided conflicting answers. Results might not be sound." );
969
+ else if (canBeTrue == CheckResult::UNKNOWN || canBeFalse == CheckResult::UNKNOWN)
970
+ {
971
+ // Not enough information to make definite claims.
972
+ }
973
+ else if (canBeTrue == CheckResult::SATISFIABLE && canBeFalse == CheckResult::SATISFIABLE)
974
+ {
975
+ // Condition can be both true and false for some program runs.
976
+ }
977
+
978
+ else if (canBeTrue == CheckResult::UNSATISFIABLE && canBeFalse == CheckResult::UNSATISFIABLE)
979
+ m_errorReporter.warning (2512_error, _condition.location (), " BMC: Condition unreachable." , SMTEncoder::callStackMessage (m_callStack));
980
+ else
981
+ {
982
+ std::string description;
983
+ if (canBeFalse == smtutil::CheckResult::UNSATISFIABLE)
984
+ {
985
+ smtAssert (canBeTrue == smtutil::CheckResult::SATISFIABLE);
986
+ description = " BMC: Condition is always true." ;
987
+ }
988
+ else
989
+ {
990
+ smtAssert (canBeTrue == smtutil::CheckResult::UNSATISFIABLE);
991
+ smtAssert (canBeFalse == smtutil::CheckResult::SATISFIABLE);
992
+ description = " BMC: Condition is always false." ;
993
+ }
994
+ m_errorReporter.warning (
995
+ 6838_error,
996
+ _condition.location (),
997
+ description,
998
+ SMTEncoder::callStackMessage (m_callStack)
999
+ );
1000
+ }
1001
+
967
1002
}
968
1003
969
1004
void BMC::checkUnderflow (BMCVerificationTarget& _target)
@@ -1068,6 +1103,7 @@ void BMC::addVerificationTarget(
1068
1103
Expression const * _expression
1069
1104
)
1070
1105
{
1106
+ smtAssert (_type != VerificationTargetType::ConstantCondition, " Checks for constant condition are handled separately" );
1071
1107
if (!m_settings.targets .has (_type) || (m_currentContract && !shouldAnalyzeVerificationTargetsFor (*m_currentContract)))
1072
1108
return ;
1073
1109
@@ -1081,10 +1117,7 @@ void BMC::addVerificationTarget(
1081
1117
m_callStack,
1082
1118
modelExpressions ()
1083
1119
};
1084
- if (_type == VerificationTargetType::ConstantCondition)
1085
- checkVerificationTarget (target);
1086
- else
1087
- m_verificationTargets.emplace_back (std::move (target));
1120
+ m_verificationTargets.emplace_back (std::move (target));
1088
1121
}
1089
1122
1090
1123
// / Solving.
@@ -1188,62 +1221,22 @@ void BMC::checkCondition(
1188
1221
m_interface->pop ();
1189
1222
}
1190
1223
1191
- void BMC::checkBooleanNotConstant (
1192
- Expression const & _condition,
1224
+ BMC::ConstantExpressionCheckResult BMC::checkBooleanNotConstant (
1193
1225
smtutil::Expression const & _constraints,
1194
- smtutil::Expression const & _value,
1195
- std::vector<SMTEncoder::CallStackEntry> const & _callStack
1226
+ smtutil::Expression const & _condition
1196
1227
)
1197
1228
{
1198
- // Do not check for const-ness if this is a constant.
1199
- if (dynamic_cast <Literal const *>(&_condition))
1200
- return ;
1201
-
1202
1229
m_interface->push ();
1203
- m_interface->addAssertion (_constraints && _value );
1230
+ m_interface->addAssertion (_constraints && _condition );
1204
1231
auto positiveResult = checkSatisfiable ();
1205
1232
m_interface->pop ();
1206
1233
1207
1234
m_interface->push ();
1208
- m_interface->addAssertion (_constraints && !_value );
1235
+ m_interface->addAssertion (_constraints && !_condition );
1209
1236
auto negatedResult = checkSatisfiable ();
1210
1237
m_interface->pop ();
1211
1238
1212
- if (positiveResult == smtutil::CheckResult::ERROR || negatedResult == smtutil::CheckResult::ERROR)
1213
- m_errorReporter.warning (8592_error, _condition.location (), " BMC: Error trying to invoke SMT solver." );
1214
- else if (positiveResult == smtutil::CheckResult::CONFLICTING || negatedResult == smtutil::CheckResult::CONFLICTING)
1215
- m_errorReporter.warning (3356_error, _condition.location (), " BMC: At least two SMT solvers provided conflicting answers. Results might not be sound." );
1216
- else if (positiveResult == smtutil::CheckResult::SATISFIABLE && negatedResult == smtutil::CheckResult::SATISFIABLE)
1217
- {
1218
- // everything fine.
1219
- }
1220
- else if (positiveResult == smtutil::CheckResult::UNKNOWN || negatedResult == smtutil::CheckResult::UNKNOWN)
1221
- {
1222
- // can't do anything.
1223
- }
1224
- else if (positiveResult == smtutil::CheckResult::UNSATISFIABLE && negatedResult == smtutil::CheckResult::UNSATISFIABLE)
1225
- m_errorReporter.warning (2512_error, _condition.location (), " BMC: Condition unreachable." , SMTEncoder::callStackMessage (_callStack));
1226
- else
1227
- {
1228
- std::string description;
1229
- if (positiveResult == smtutil::CheckResult::SATISFIABLE)
1230
- {
1231
- solAssert (negatedResult == smtutil::CheckResult::UNSATISFIABLE, " " );
1232
- description = " BMC: Condition is always true." ;
1233
- }
1234
- else
1235
- {
1236
- solAssert (positiveResult == smtutil::CheckResult::UNSATISFIABLE, " " );
1237
- solAssert (negatedResult == smtutil::CheckResult::SATISFIABLE, " " );
1238
- description = " BMC: Condition is always false." ;
1239
- }
1240
- m_errorReporter.warning (
1241
- 6838_error,
1242
- _condition.location (),
1243
- description,
1244
- SMTEncoder::callStackMessage (_callStack)
1245
- );
1246
- }
1239
+ return {.canBeTrue = positiveResult, .canBeFalse = negatedResult};
1247
1240
}
1248
1241
1249
1242
std::pair<smtutil::CheckResult, std::vector<std::string>>
0 commit comments