@@ -59,6 +59,26 @@ static bool isDereferenceOp(const Token* tok)
5959 return tok->str () == " ." && tok->originalName () == " ->" ;
6060}
6161
62+ // Every leaf is a constant or has an int value or constraint in the memory, so an undecided
63+ // condition can go either way.
64+ static bool stateCoversCondition (const Token* tok, const ProgramMemory& pm, int depth = 20 )
65+ {
66+ if (!tok || depth < 0 )
67+ return false ;
68+ if (tok->hasKnownIntValue ())
69+ return true ;
70+ if (tok->varId () > 0 || Token::simpleMatch (tok, " ." )) {
71+ const ProgramMemory::Values* values = pm.getValues (tok->exprId ());
72+ return values && !values->empty () && std::all_of (values->cbegin (), values->cend (), [](const ValueFlow::Value& v) {
73+ return v.isIntValue ();
74+ });
75+ }
76+ if (!tok->astOperand2 ())
77+ return Token::Match (tok, " !|-|~" ) && stateCoversCondition (tok->astOperand1 (), pm, depth - 1 );
78+ return tok->isConstOp () && stateCoversCondition (tok->astOperand1 (), pm, depth - 1 ) &&
79+ stateCoversCondition (tok->astOperand2 (), pm, depth - 1 );
80+ }
81+
6282struct ValueFlowAnalyzer : Analyzer {
6383 RefThunk<const Settings> settings;
6484 ProgramMemoryState pms;
@@ -383,6 +403,15 @@ struct ValueFlowAnalyzer : Analyzer {
383403 assert (false && " Internal update unimplemented." );
384404 }
385405
406+ // A conditional value is split only on a condition the state covers; an unknown one may be
407+ // correlated with the assumption.
408+ bool canSplitConditional (const Token* condTok) const
409+ {
410+ if (!condTok)
411+ return false ;
412+ return stateCoversCondition (condTok, pms.get (condTok, nullptr , getProgramState ()));
413+ }
414+
386415private:
387416 // Returns Action::Match if its an exact match, return Action::Read if it partially matches the lifetime
388417 Action analyzeLifetime (const Token* tok) const
@@ -757,14 +786,13 @@ struct ValueFlowAnalyzer : Analyzer {
757786 pms.addState (anchor, getProgramState ());
758787 pms.assume (tok, state, flags & Assume::ContainerEmpty, origin);
759788
760- // The false path (the true path uses scopeEnd above): record the assumed state where control
761- // continues - the end of the else block, or the closing brace when there is no else - so it
762- // reaches the enclosing scope.
789+ // The false path: record the state where control continues, at the end of the else block or
790+ // past the closing brace (which still counts as inside the block).
763791 if (isCondBlock && !(flags & Assume::Pending) && !state) {
764792 if (Token::simpleMatch (endBlock, " } else {" ))
765793 pms.addState (endBlock->linkAt (2 )->previous (), getProgramState ());
766794 else
767- pms.addState (endBlock, getProgramState ());
795+ pms.addState (endBlock-> next () , getProgramState ());
768796 }
769797
770798 if (!(flags & Assume::Quiet)) {
@@ -1051,7 +1079,7 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
10511079
10521080 bool stopOnCondition (const Token* condTok) const override {
10531081 if (isConditional ())
1054- return true ;
1082+ return ! canSplitConditional (condTok) ;
10551083 if (!condTok->hasKnownIntValue () && values.count (condTok->varId ()) == 0 ) {
10561084 const auto & values_ = condTok->values ();
10571085 return std::any_of (values_.cbegin (), values_.cend (), [](const ValueFlow::Value& v) {
@@ -1083,9 +1111,9 @@ struct MultiValueFlowAnalyzer : ValueFlowAnalyzer {
10831111 };
10841112 if (std::all_of (values.cbegin (), values.cend (), std::bind (pred, std::bind (SelectMapValues{}, std::placeholders::_1))))
10851113 return true ;
1086- if (isConditional ())
1087- return false ;
10881114 const Token* condTok = getCondTokFromEnd (endBlock);
1115+ if (isConditional ())
1116+ return canSplitConditional (condTok);
10891117 std::set<nonneg int > varids;
10901118 std::transform (getVars ().cbegin (), getVars ().cend (), std::inserter (varids, varids.begin ()), SelectMapKeys{});
10911119 return bifurcate (condTok, varids, getSettings ());
@@ -1232,9 +1260,9 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
12321260 if (value.isLifetimeValue ())
12331261 return false ;
12341262 // 'conditional' flag (uninit, or lowered after a modifying branch): may depend on a
1235- // condition that doesn't mention the variable -> stop
1263+ // condition that doesn't mention the variable -> stop unless the state covers this one
12361264 if (value.conditional && !value.isKnown ())
1237- return true ;
1265+ return ! canSplitConditional (condTok) ;
12381266 if (value.isNonValue ())
12391267 return false ;
12401268 if (value.isSymbolicValue ())
@@ -1272,9 +1300,9 @@ struct SingleValueFlowAnalyzer : ValueFlowAnalyzer {
12721300 return true ;
12731301 if (value.isLifetimeValue ())
12741302 return true ;
1275- if (isConditional ())
1276- return false ;
12771303 const Token* condTok = getCondTokFromEnd (endBlock);
1304+ if (isConditional ())
1305+ return canSplitConditional (condTok);
12781306 std::set<nonneg int > varids2;
12791307 std::transform (getVars ().cbegin (), getVars ().cend (), std::inserter (varids2, varids2.begin ()), SelectMapKeys{});
12801308 return bifurcate (condTok, varids2, getSettings ());
0 commit comments