@@ -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
@@ -690,12 +678,7 @@ void BMC::visitRequire(FunctionCall const& _funCall)
690678 auto const & args = _funCall.arguments ();
691679 solAssert (args.size () >= 1 , " " );
692680 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 ());
699682}
700683
701684void BMC::visitAddMulMod (FunctionCall const & _funCall)
@@ -933,9 +916,6 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
933916
934917 switch (_target.type )
935918 {
936- case VerificationTargetType::ConstantCondition:
937- checkConstantCondition (_target);
938- break ;
939919 case VerificationTargetType::Underflow:
940920 checkUnderflow (_target);
941921 break ;
@@ -951,19 +931,70 @@ void BMC::checkVerificationTarget(BMCVerificationTarget& _target)
951931 case VerificationTargetType::Assert:
952932 checkAssert (_target);
953933 break ;
934+ case VerificationTargetType::ConstantCondition:
935+ solAssert (false , " Checks for constant condition are handled separately" );
954936 default :
955937 solAssert (false , " " );
956938 }
957939}
958940
959- void BMC::checkConstantCondition (BMCVerificationTarget& _target )
941+ void BMC::checkIfConditionIsConstant (Expression const & _condition )
960942{
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+
967998}
968999
9691000void BMC::checkUnderflow (BMCVerificationTarget& _target)
@@ -1068,6 +1099,7 @@ void BMC::addVerificationTarget(
10681099 Expression const * _expression
10691100)
10701101{
1102+ smtAssert (_type != VerificationTargetType::ConstantCondition, " Checks for constant condition are handled separately" );
10711103 if (!m_settings.targets .has (_type) || (m_currentContract && !shouldAnalyzeVerificationTargetsFor (*m_currentContract)))
10721104 return ;
10731105
@@ -1081,10 +1113,7 @@ void BMC::addVerificationTarget(
10811113 m_callStack,
10821114 modelExpressions ()
10831115 };
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));
10881117}
10891118
10901119// / Solving.
@@ -1188,62 +1217,22 @@ void BMC::checkCondition(
11881217 m_interface->pop ();
11891218}
11901219
1191- void BMC::checkBooleanNotConstant (
1192- Expression const & _condition,
1220+ BMC::ConstantExpressionCheckResult BMC::checkBooleanNotConstant (
11931221 smtutil::Expression const & _constraints,
1194- smtutil::Expression const & _value,
1195- std::vector<SMTEncoder::CallStackEntry> const & _callStack
1222+ smtutil::Expression const & _condition
11961223)
11971224{
1198- // Do not check for const-ness if this is a constant.
1199- if (dynamic_cast <Literal const *>(&_condition))
1200- return ;
1201-
12021225 m_interface->push ();
1203- m_interface->addAssertion (_constraints && _value );
1226+ m_interface->addAssertion (_constraints && _condition );
12041227 auto positiveResult = checkSatisfiable ();
12051228 m_interface->pop ();
12061229
12071230 m_interface->push ();
1208- m_interface->addAssertion (_constraints && !_value );
1231+ m_interface->addAssertion (_constraints && !_condition );
12091232 auto negatedResult = checkSatisfiable ();
12101233 m_interface->pop ();
12111234
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};
12471236}
12481237
12491238std::pair<smtutil::CheckResult, std::vector<std::string>>
0 commit comments