[clang] [StaticAnalyzer] Fix state update in VisitObjCForCollectionStmt (PR #124477)

Ziqing Luo via cfe-commits cfe-commits at lists.llvm.org
Sun Jan 26 12:08:19 PST 2025


================
@@ -124,24 +124,26 @@ void ExprEngine::VisitObjCForCollectionStmt(const ObjCForCollectionStmt *S,
 
   bool isContainerNull = state->isNull(collectionV).isConstrainedTrue();
 
-  ExplodedNodeSet dstLocation;
-  evalLocation(dstLocation, S, elem, Pred, state, elementV, false);
----------------
ziqingluo-90 wrote:

To elaborate the issue, suppose `evalLocation` alters the `Pred` state and populates the new states in `dstLocation`. (This name `dstLocation` is a bit confusing IMO, let's call those new states `NewPreds` instead.)  However,  the `StmtNodeBuilder` below still takes `Pred` as the source state (old line 131) while the next transitions computed in `populateObjCForDestinationSet` are computed from `NewPreds` (old line 134 & 138).

The confusion here is that there suppose to be transitions:
`Pred --evalLocation--> NewPreds --populateObjCForDestinationSet--> Dest`
but the `StmtNodeBuilder` used for the second transition above assumes the source state is `Pred` instead of `NewPreds`.   This is what's wrong with this function `VisitObjCForCollectionStmt`.

Then how does the bug lead to a crash?

The way `StmtNodeBuilder` works is that it maintains a `Frontier` set---the set of states to be explored next.   After initialization (old line 131),  `Frontier = {Pred}`.    In `populateObjCForDestinationSet`, `StmtNodeBuilder` is used to generate `Dest` and remove source state from the set.  Note that `NewPreds` are passed to `populateObjCForDestinationSet` as source states.  So `StmtNodeBuilder` attempts to remove `NewPreds` from the set, which does not change the set.   Finally, `Frontier = {Pred, Dest}`.

Starting from this ill-formed `Frontier` set, the engine executes [`hasMoreIterations`](https://github.com/llvm/llvm-project/blob/e8e75e08c9214fe25b56535fc26f5435a875a137/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp#L2709C1-L2714C2) on them.   The assertion fails on the state `Pred` because it has never been set the `ObjCForHasMoreIterations` map. `Dest` has the map set.  This is what `populateObjCForDestinationSet` does.   (If assertions are disabled, there is a segmentation fault.) 




https://github.com/llvm/llvm-project/pull/124477


More information about the cfe-commits mailing list