@@ -1149,3 +1149,55 @@ private int countNumberOfBranchesUsingParameter(SwitchInstruction switch, Parame
1149
1149
)
1150
1150
)
1151
1151
}
1152
+
1153
+ /**
1154
+ * Holds if the data-flow step from `node1` to `node2` can be used to
1155
+ * determine where side-effects may return from a callable.
1156
+ * For C/C++, this means that the step from `node1` to `node2` not only
1157
+ * preserves the value, but also preserves the identity of the value.
1158
+ * For example, the assignment to `x` that reads the value of `*p` in
1159
+ * ```cpp
1160
+ * int* p = ...
1161
+ * int x = *p;
1162
+ * ```
1163
+ * does not preserve the identity of `*p`.
1164
+ */
1165
+ bindingset [ node1, node2]
1166
+ pragma [ inline_late]
1167
+ predicate validParameterAliasStep ( Node node1 , Node node2 ) {
1168
+ // When flow-through summaries are computed we track which parameters flow to out-going parameters.
1169
+ // In an example such as:
1170
+ // ```
1171
+ // modify(int* px) { *px = source(); }
1172
+ // void modify_copy(int* p) {
1173
+ // int x = *p;
1174
+ // modify(&x);
1175
+ // }
1176
+ // ```
1177
+ // since dataflow tracks each indirection as a separate SSA variable dataflow
1178
+ // sees the above roughly as
1179
+ // ```
1180
+ // modify(int* px, int deref_px) { deref_px = source(); }
1181
+ // void modify_copy(int* p, int deref_p) {
1182
+ // int x = deref_p;
1183
+ // modify(&x, x);
1184
+ // }
1185
+ // ```
1186
+ // and when dataflow computes flow from a parameter to a post-update node to
1187
+ // conclude which parameters are "updated" by the call to `modify_copy` it
1188
+ // finds flow from `x [post update]` to `deref_p [post update]`.
1189
+ // To prevent this we exclude steps that don't preserve identity. We do this
1190
+ // by excluding flow from the right-hand side of `StoreInstruction`s to the
1191
+ // `StoreInstruction`. This is sufficient because, for flow-through summaries,
1192
+ // we're only interested in indirect parameters such as `deref_p` in the
1193
+ // exampe above (i.e., the parameters with a non-zero indirection index), and
1194
+ // if that ever flows to the right-hand side of a `StoreInstruction` then
1195
+ // there must have been a dereference to reduce its indirection index down to
1196
+ // 0.
1197
+ not exists ( Operand operand |
1198
+ node1 .asOperand ( ) = operand and
1199
+ node2 .asInstruction ( ) .( StoreInstruction ) .getSourceValueOperand ( ) = operand
1200
+ )
1201
+ // TODO: Also block flow through models that don't preserve identity such
1202
+ // as `strdup`.
1203
+ }
0 commit comments