@@ -1046,6 +1046,102 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
10461046 }
10471047
10481048 private module ReverseFlow {
1049+ module Cand {
1050+ /**
1051+ * Holds if `p` can flow to `node` in the same callable using only
1052+ * value-preserving steps.
1053+ *
1054+ * `read` indicates whether it is contents of `p` that can flow to `node`.
1055+ */
1056+ pragma [ nomagic]
1057+ private predicate parameterValueFlowCand ( ParamNode p , Node node ) {
1058+ (
1059+ p = node
1060+ or
1061+ // local flow
1062+ exists ( Node mid |
1063+ parameterValueFlowCand ( p , mid ) and
1064+ simpleLocalFlowStep ( mid , node , _) and
1065+ validParameterAliasStep ( mid , node )
1066+ )
1067+ or
1068+ // store
1069+ exists ( Node mid |
1070+ parameterValueFlowCand ( p , mid ) and
1071+ Lang:: storeStep ( mid , _, node )
1072+ )
1073+ or
1074+ // read
1075+ exists ( Node mid |
1076+ parameterValueFlowCand ( p , mid ) and
1077+ Lang:: readStep ( mid , _, node )
1078+ )
1079+ or
1080+ // flow through
1081+ exists ( ArgNode arg |
1082+ parameterValueFlowArgCand ( p , arg ) and
1083+ argumentValueFlowsThroughCand ( arg , node )
1084+ )
1085+ )
1086+ }
1087+
1088+ pragma [ nomagic]
1089+ private predicate parameterValueFlowArgCand ( ParamNode p , ArgNode arg ) {
1090+ parameterValueFlowCand ( p , arg )
1091+ }
1092+
1093+ pragma [ nomagic]
1094+ predicate parameterValueFlowsToPreUpdateCand ( ParamNode p , PostUpdateNode n ) {
1095+ parameterValueFlowCand ( p , n .getPreUpdateNode ( ) )
1096+ }
1097+
1098+ /**
1099+ * Holds if `p` can flow to a return node of kind `kind` in the same
1100+ * callable using only value-preserving steps, not taking call contexts
1101+ * into account.
1102+ *
1103+ * `read` indicates whether it is contents of `p` that can flow to the return
1104+ * node.
1105+ */
1106+ predicate parameterValueFlowReturnCand ( ParamNode p , ReturnKind kind ) {
1107+ exists ( ReturnNode ret |
1108+ parameterValueFlowCand ( p , ret ) and
1109+ kind = ret .getKind ( )
1110+ )
1111+ }
1112+
1113+ pragma [ nomagic]
1114+ private predicate argumentValueFlowsThroughCand0 (
1115+ DataFlowCall call , ArgNode arg , ReturnKind kind
1116+ ) {
1117+ exists ( ParamNode param | viableParamArg ( call , param , arg ) |
1118+ parameterValueFlowReturnCand ( param , kind )
1119+ )
1120+ }
1121+
1122+ /**
1123+ * Holds if `arg` flows to `out` through a call using only value-preserving steps,
1124+ * not taking call contexts into account.
1125+ *
1126+ * `read` indicates whether it is contents of `arg` that can flow to `out`.
1127+ */
1128+ predicate argumentValueFlowsThroughCand ( ArgNode arg , Node out ) {
1129+ exists ( DataFlowCall call , ReturnKind kind |
1130+ argumentValueFlowsThroughCand0 ( call , arg , kind ) and
1131+ out = getAnOutNode ( call , kind )
1132+ )
1133+ }
1134+
1135+ predicate cand ( ParamNode p , Node n ) {
1136+ parameterValueFlowCand ( p , n ) and
1137+ (
1138+ parameterValueFlowReturnCand ( p , _)
1139+ or
1140+ parameterValueFlowsToPreUpdateCand ( p , _)
1141+ )
1142+ }
1143+ }
1144+
10491145 /**
10501146 * Holds if the local step from `arg` to `out` actually models a flow-through
10511147 * step.
@@ -2091,7 +2187,9 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
20912187 newtype TNodeEx =
20922188 TNodeNormal ( Node n ) or
20932189 TNodeImplicitRead ( Node n ) or // will be restricted to nodes with actual implicit reads in `DataFlowImpl.qll`
2094- TNodeReverse ( Node n , Boolean allowFwdFlowOut )
2190+ TNodeReverse ( Node n , Boolean allowFwdFlowOut ) {
2191+ ReverseFlow:: Cand:: cand ( _, n ) or n = any ( PostUpdateNode p ) .getPreUpdateNode ( )
2192+ }
20952193
20962194 /**
20972195 * Holds if data can flow in one local step from `node1` to `node2`.
0 commit comments