Skip to content

Commit ef2caa3

Browse files
committed
C++: Add a new API for mapping a dataflow node to a definition. This means we can reduce duplication from 'asExpr'.
1 parent ab62606 commit ef2caa3

File tree

1 file changed

+123
-17
lines changed

1 file changed

+123
-17
lines changed

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 123 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,54 @@ class Node extends TIRDataFlowNode {
260260
*/
261261
Expr asDefiningArgument() { result = this.asDefiningArgument(_) }
262262

263+
/**
264+
* Gets the definition associated with this node, if any.
265+
*
266+
* For example, consider the following example
267+
* ```cpp
268+
* int x = 42; // 1
269+
* x = 34; // 2
270+
* ++x; // 3
271+
* x++; // 4
272+
* x += 1; // 5
273+
* int y = x += 2; // 6
274+
* ```
275+
* - For (1) the result is `42`.
276+
* - For (2) the result is `x = 34`.
277+
* - For (3) the result is `++x`.
278+
* - For (4) the result is `x++`.
279+
* - For (5) the result is `x += 1`.
280+
* - For (6) there are two results:
281+
* - For the definition generated by `x += 2` the result is `x += 2`
282+
* - For the definition generated by `int y = ...` the result is
283+
* also `x += 2`
284+
*/
285+
Expr asDefinition() {
286+
exists(StoreInstruction store |
287+
store = this.asInstruction() and
288+
result = asDefinitionImpl(store)
289+
)
290+
}
291+
292+
/**
293+
* Gets the indirect definition at a given indirection corresponding to this
294+
* node, if any.
295+
*
296+
* See the comments on `Node.asDefinition` for examples.
297+
*/
298+
Expr asIndirectDefinition(int indirectionIndex) {
299+
exists(StoreInstruction store |
300+
this.(IndirectInstruction).hasInstructionAndIndirectionIndex(store, indirectionIndex) and
301+
result = asDefinitionImpl(store)
302+
)
303+
}
304+
305+
/**
306+
* Gets the indirect definition at some indirection corresponding to this
307+
* node, if any.
308+
*/
309+
Expr asIndirectDefinition() { result = this.asIndirectDefinition(_) }
310+
263311
/**
264312
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
265313
*
@@ -1142,22 +1190,6 @@ private module GetConvertedResultExpression {
11421190
}
11431191

11441192
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
1145-
// For an expression such as `i += 2` we pretend that the generated
1146-
// `StoreInstruction` contains the result of the expression even though
1147-
// this isn't totally aligned with the C/C++ standard.
1148-
exists(TranslatedAssignOperation tao |
1149-
result = tao.getExpr() and
1150-
instr = tao.getInstruction(any(AssignmentStoreTag tag))
1151-
)
1152-
or
1153-
// Similarly for `i++` and `++i` we pretend that the generated
1154-
// `StoreInstruction` is contains the result of the expression even though
1155-
// this isn't totally aligned with the C/C++ standard.
1156-
exists(TranslatedCrementOperation tco |
1157-
result = tco.getExpr() and
1158-
instr = tco.getInstruction(any(CrementStoreTag tag))
1159-
)
1160-
or
11611193
// IR construction inserts an additional cast to a `size_t` on the extent
11621194
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
11631195
// a result for `getConvertedResultExpression`. We remap this here so that
@@ -1182,6 +1214,75 @@ private module GetConvertedResultExpression {
11821214
not exists(getConvertedResultExpressionImpl0(instr)) and
11831215
result = instr.getConvertedResultExpression()
11841216
}
1217+
1218+
/**
1219+
* Gets the result for `node.asDefinition()` (when `node` is the instruction
1220+
* node that wraps `store`) in the cases where `store.getAst()` should not be
1221+
* used to define the result of `node.asDefinition()`.
1222+
*/
1223+
private Expr asDefinitionImpl0(StoreInstruction store) {
1224+
// For an expression such as `i += 2` we pretend that the generated
1225+
// `StoreInstruction` contains the result of the expression even though
1226+
// this isn't totally aligned with the C/C++ standard.
1227+
exists(TranslatedAssignOperation tao |
1228+
store = tao.getInstruction(any(AssignmentStoreTag tag)) and
1229+
result = tao.getExpr()
1230+
)
1231+
or
1232+
// Similarly for `i++` and `++i` we pretend that the generated
1233+
// `StoreInstruction` is contains the result of the expression even though
1234+
// this isn't totally aligned with the C/C++ standard.
1235+
exists(TranslatedCrementOperation tco |
1236+
store = tco.getInstruction(any(CrementStoreTag tag)) and
1237+
result = tco.getExpr()
1238+
)
1239+
}
1240+
1241+
/**
1242+
* Holds if the expression returned by `store.getAst()` should not be
1243+
* returned as the result of `node.asDefinition()` when `node` is the
1244+
* instruction node that wraps `store`.
1245+
*/
1246+
private predicate excludeAsDefinitionResult(StoreInstruction store) {
1247+
// Exclude the store to the temporary generated by a ternary expression.
1248+
exists(TranslatedConditionalExpr tce |
1249+
store = tce.getInstruction(any(ConditionValueFalseStoreTag tag))
1250+
or
1251+
store = tce.getInstruction(any(ConditionValueTrueStoreTag tag))
1252+
)
1253+
}
1254+
1255+
/**
1256+
* Gets the expression that represents the result of `StoreInstruction` for
1257+
* dataflow purposes.
1258+
*
1259+
* For example, consider the following example
1260+
* ```cpp
1261+
* int x = 42; // 1
1262+
* x = 34; // 2
1263+
* ++x; // 3
1264+
* x++; // 4
1265+
* x += 1; // 5
1266+
* int y = x += 2; // 6
1267+
* ```
1268+
* For (1) the result is `42`.
1269+
* For (2) the result is `x = 34`.
1270+
* For (3) the result is `++x`.
1271+
* For (4) the result is `x++`.
1272+
* For (5) the result is `x += 1`.
1273+
* For (6) there are two results:
1274+
* - For the `StoreInstruction` generated by `x += 2` the result
1275+
* is `x += 2`
1276+
* - For the `StoreInstruction` generated by `int y = ...` the result
1277+
* is also `x += 2`
1278+
*/
1279+
Expr asDefinitionImpl(StoreInstruction store) {
1280+
not exists(asDefinitionImpl0(store)) and
1281+
not excludeAsDefinitionResult(store) and
1282+
result = store.getAst().(Expr).getUnconverted()
1283+
or
1284+
result = asDefinitionImpl0(store)
1285+
}
11851286
}
11861287

11871288
private import GetConvertedResultExpression
@@ -1947,7 +2048,12 @@ module ExprFlowCached {
19472048
isIndirectBaseOfArrayAccess(n, result)
19482049
or
19492050
not isIndirectBaseOfArrayAccess(n, _) and
1950-
result = n.asExpr()
2051+
(
2052+
result = n.asExpr()
2053+
or
2054+
result = n.asDefinition() and
2055+
result instanceof CrementOperation
2056+
)
19512057
}
19522058

19532059
/**

0 commit comments

Comments
 (0)