@@ -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
@@ -690,12 +678,7 @@ void BMC::visitRequire(FunctionCall const& _funCall)
690
678
auto const & args = _funCall.arguments ();
691
679
solAssert (args.size () >= 1 , " " );
692
680
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
- );
681
+ checkIfConditionIsConstant (*args.front ());
699
682
}
700
683
701
684
void BMC::visitAddMulMod (FunctionCall const & _funCall)
@@ -933,9 +916,6 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
933
916
934
917
switch (_target.type )
935
918
{
936
- case VerificationTargetType::ConstantCondition:
937
- checkConstantCondition (_target);
938
- break ;
939
919
case VerificationTargetType::Underflow:
940
920
checkUnderflow (_target);
941
921
break ;
@@ -951,19 +931,70 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
951
931
case VerificationTargetType::Assert:
952
932
checkAssert (_target);
953
933
break ;
934
+ case VerificationTargetType::ConstantCondition:
935
+ solAssert (false , " Checks for constant condition are handled separately" );
954
936
default :
955
937
solAssert (false , " " );
956
938
}
957
939
}
958
940
959
- void BMC::checkConstantCondition (BMCVerificationTarget& _target )
941
+ void BMC::checkIfConditionIsConstant (Expression const & _condition )
960
942
{
961
- checkBooleanNotConstant (
962
- *_target.expression ,
963
- _target.constraints ,
964
- _target.value ,
965
- _target.callStack
966
- );
943
+ if (
944
+ !m_settings.targets .has (VerificationTargetType::ConstantCondition) ||
945
+ (m_currentContract && !shouldEncode (*m_currentContract))
946
+ )
947
+ return ;
948
+
949
+ // We ignore called functions here because they have specific input values.
950
+ // Also, expressions inside loop can have different values in different iterations.
951
+ if (!isRootFunction () || isInsideLoop ())
952
+ return ;
953
+
954
+ // Do not check for const-ness if this is a literal.
955
+ if (dynamic_cast <Literal const *>(&_condition))
956
+ return ;
957
+
958
+ auto [canBeTrue, canBeFalse] = checkBooleanNotConstant (currentPathConditions () && m_context.assertions (), expr (_condition));
959
+
960
+ // Report based on the result of the checks
961
+ if (canBeTrue == CheckResult::ERROR || canBeFalse == CheckResult::ERROR)
962
+ m_errorReporter.warning (8592_error, _condition.location (), " BMC: Error trying to invoke SMT solver." );
963
+ else if (canBeTrue == CheckResult::CONFLICTING || canBeFalse == CheckResult::CONFLICTING)
964
+ m_errorReporter.warning (3356_error, _condition.location (), " BMC: At least two SMT solvers provided conflicting answers. Results might not be sound." );
965
+ else if (canBeTrue == CheckResult::UNKNOWN || canBeFalse == CheckResult::UNKNOWN)
966
+ {
967
+ // Not enough information to make definite claims.
968
+ }
969
+ else if (canBeTrue == CheckResult::SATISFIABLE && canBeFalse == CheckResult::SATISFIABLE)
970
+ {
971
+ // Condition can be both true and false for some program runs.
972
+ }
973
+
974
+ else if (canBeTrue == CheckResult::UNSATISFIABLE && canBeFalse == CheckResult::UNSATISFIABLE)
975
+ m_errorReporter.warning (2512_error, _condition.location (), " BMC: Condition unreachable." , SMTEncoder::callStackMessage (m_callStack));
976
+ else
977
+ {
978
+ std::string description;
979
+ if (canBeFalse == smtutil::CheckResult::UNSATISFIABLE)
980
+ {
981
+ smtAssert (canBeTrue == smtutil::CheckResult::SATISFIABLE);
982
+ description = " BMC: Condition is always true." ;
983
+ }
984
+ else
985
+ {
986
+ smtAssert (canBeTrue == smtutil::CheckResult::UNSATISFIABLE);
987
+ smtAssert (canBeFalse == smtutil::CheckResult::SATISFIABLE);
988
+ description = " BMC: Condition is always false." ;
989
+ }
990
+ m_errorReporter.warning (
991
+ 6838_error,
992
+ _condition.location (),
993
+ description,
994
+ SMTEncoder::callStackMessage (m_callStack)
995
+ );
996
+ }
997
+
967
998
}
968
999
969
1000
void BMC::checkUnderflow (BMCVerificationTarget& _target)
@@ -1068,6 +1099,7 @@ void BMC::addVerificationTarget(
1068
1099
Expression const * _expression
1069
1100
)
1070
1101
{
1102
+ smtAssert (_type != VerificationTargetType::ConstantCondition, " Checks for constant condition are handled separately" );
1071
1103
if (!m_settings.targets .has (_type) || (m_currentContract && !shouldAnalyzeVerificationTargetsFor (*m_currentContract)))
1072
1104
return ;
1073
1105
@@ -1081,10 +1113,7 @@ void BMC::addVerificationTarget(
1081
1113
m_callStack,
1082
1114
modelExpressions ()
1083
1115
};
1084
- if (_type == VerificationTargetType::ConstantCondition)
1085
- checkVerificationTarget (target);
1086
- else
1087
- m_verificationTargets.emplace_back (std::move (target));
1116
+ m_verificationTargets.emplace_back (std::move (target));
1088
1117
}
1089
1118
1090
1119
// / Solving.
@@ -1188,62 +1217,22 @@ void BMC::checkCondition(
1188
1217
m_interface->pop ();
1189
1218
}
1190
1219
1191
- void BMC::checkBooleanNotConstant (
1192
- Expression const & _condition,
1220
+ BMC::ConstantExpressionCheckResult BMC::checkBooleanNotConstant (
1193
1221
smtutil::Expression const & _constraints,
1194
- smtutil::Expression const & _value,
1195
- std::vector<SMTEncoder::CallStackEntry> const & _callStack
1222
+ smtutil::Expression const & _condition
1196
1223
)
1197
1224
{
1198
- // Do not check for const-ness if this is a constant.
1199
- if (dynamic_cast <Literal const *>(&_condition))
1200
- return ;
1201
-
1202
1225
m_interface->push ();
1203
- m_interface->addAssertion (_constraints && _value );
1226
+ m_interface->addAssertion (_constraints && _condition );
1204
1227
auto positiveResult = checkSatisfiable ();
1205
1228
m_interface->pop ();
1206
1229
1207
1230
m_interface->push ();
1208
- m_interface->addAssertion (_constraints && !_value );
1231
+ m_interface->addAssertion (_constraints && !_condition );
1209
1232
auto negatedResult = checkSatisfiable ();
1210
1233
m_interface->pop ();
1211
1234
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
- }
1235
+ return {.canBeTrue = positiveResult, .canBeFalse = negatedResult};
1247
1236
}
1248
1237
1249
1238
std::pair<smtutil::CheckResult, std::vector<std::string>>
0 commit comments