@@ -247,14 +247,8 @@ bool BMC::visit(IfStatement const& _node)
247247 m_context.pushSolver ();
248248 _node.condition ().accept (*this );
249249
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+
258252 m_context.popSolver ();
259253 resetVariableIndices (std::move (indicesBeforePush));
260254
@@ -283,13 +277,7 @@ bool BMC::visit(Conditional const& _op)
283277 auto indicesBeforePush = copyVariableIndices ();
284278 m_context.pushSolver ();
285279 _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 ());
293281 m_context.popSolver ();
294282 resetVariableIndices (std::move (indicesBeforePush));
295283
@@ -375,7 +363,9 @@ bool BMC::visit(WhileStatement const& _node)
375363 {
376364 // after loop iterations are done, we check the loop condition last final time
377365 auto indices = copyVariableIndices ();
366+ m_loopCheckpoints.emplace ();
378367 _node.condition ().accept (*this );
368+ m_loopCheckpoints.pop ();
379369 loopCondition = expr (_node.condition ());
380370 // assert that the loop is complete
381371 m_context.addAssertion (!loopCondition || broke || !loopConditionOnPreviousIterations);
@@ -403,13 +393,13 @@ bool BMC::visit(ForStatement const& _node)
403393 for (unsigned int i = 0 ; i < bmcLoopIterations; ++i)
404394 {
405395 auto indicesBefore = copyVariableIndices ();
396+ m_loopCheckpoints.emplace ();
406397 if (_node.condition ())
407398 {
408399 _node.condition ()->accept (*this );
409400 // values in loop condition might change during loop iteration
410401 forCondition = expr (*_node.condition ());
411402 }
412- m_loopCheckpoints.emplace ();
413403 auto indicesAfterCondition = copyVariableIndices ();
414404
415405 pushPathCondition (forCondition);
@@ -455,8 +445,10 @@ bool BMC::visit(ForStatement const& _node)
455445 auto indices = copyVariableIndices ();
456446 if (_node.condition ())
457447 {
448+ m_loopCheckpoints.emplace ();
458449 _node.condition ()->accept (*this );
459450 forCondition = expr (*_node.condition ());
451+ m_loopCheckpoints.pop ();
460452 }
461453 // assert that the loop is complete
462454 m_context.addAssertion (!forCondition || broke || !forConditionOnPreviousIterations);
@@ -690,12 +682,7 @@ void BMC::visitRequire(FunctionCall const& _funCall)
690682 auto const & args = _funCall.arguments ();
691683 solAssert (args.size () >= 1 , " " );
692684 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 ());
699686}
700687
701688void BMC::visitAddMulMod (FunctionCall const & _funCall)
@@ -933,9 +920,6 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
933920
934921 switch (_target.type )
935922 {
936- case VerificationTargetType::ConstantCondition:
937- checkConstantCondition (_target);
938- break ;
939923 case VerificationTargetType::Underflow:
940924 checkUnderflow (_target);
941925 break ;
@@ -951,19 +935,70 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
951935 case VerificationTargetType::Assert:
952936 checkAssert (_target);
953937 break ;
938+ case VerificationTargetType::ConstantCondition:
939+ smtAssert (false , " Checks for constant condition are handled separately" );
954940 default :
955- solAssert (false , " " );
941+ smtAssert (false );
956942 }
957943}
958944
959- void BMC::checkConstantCondition (BMCVerificationTarget& _target )
945+ void BMC::checkIfConditionIsConstant (Expression const & _condition )
960946{
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+
9671002}
9681003
9691004void BMC::checkUnderflow (BMCVerificationTarget& _target)
@@ -1068,6 +1103,7 @@ void BMC::addVerificationTarget(
10681103 Expression const * _expression
10691104)
10701105{
1106+ smtAssert (_type != VerificationTargetType::ConstantCondition, " Checks for constant condition are handled separately" );
10711107 if (!m_settings.targets .has (_type) || (m_currentContract && !shouldAnalyzeVerificationTargetsFor (*m_currentContract)))
10721108 return ;
10731109
@@ -1081,10 +1117,7 @@ void BMC::addVerificationTarget(
10811117 m_callStack,
10821118 modelExpressions ()
10831119 };
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));
10881121}
10891122
10901123// / Solving.
@@ -1188,62 +1221,22 @@ void BMC::checkCondition(
11881221 m_interface->pop ();
11891222}
11901223
1191- void BMC::checkBooleanNotConstant (
1192- Expression const & _condition,
1224+ BMC::ConstantExpressionCheckResult BMC::checkBooleanNotConstant (
11931225 smtutil::Expression const & _constraints,
1194- smtutil::Expression const & _value,
1195- std::vector<SMTEncoder::CallStackEntry> const & _callStack
1226+ smtutil::Expression const & _condition
11961227)
11971228{
1198- // Do not check for const-ness if this is a constant.
1199- if (dynamic_cast <Literal const *>(&_condition))
1200- return ;
1201-
12021229 m_interface->push ();
1203- m_interface->addAssertion (_constraints && _value );
1230+ m_interface->addAssertion (_constraints && _condition );
12041231 auto positiveResult = checkSatisfiable ();
12051232 m_interface->pop ();
12061233
12071234 m_interface->push ();
1208- m_interface->addAssertion (_constraints && !_value );
1235+ m_interface->addAssertion (_constraints && !_condition );
12091236 auto negatedResult = checkSatisfiable ();
12101237 m_interface->pop ();
12111238
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};
12471240}
12481241
12491242std::pair<smtutil::CheckResult, std::vector<std::string>>
0 commit comments