@@ -313,13 +313,79 @@ class Node extends TIRDataFlowNode {
313
313
* `n.asExpr() instanceof IncrementOperation` since the result of evaluating
314
314
* the expression `x++` is passed to `sink`.
315
315
*/
316
- Expr asDefinition ( ) {
317
- exists ( StoreInstruction store |
316
+ Expr asDefinition ( ) { result = this .asDefinition ( _) }
317
+
318
+ /**
319
+ * Gets the definition associated with this node, if any.
320
+ *
321
+ * For example, consider the following example
322
+ * ```cpp
323
+ * int x = 42; // 1
324
+ * x = 34; // 2
325
+ * ++x; // 3
326
+ * x++; // 4
327
+ * x += 1; // 5
328
+ * int y = x += 2; // 6
329
+ * ```
330
+ * - For (1) the result is `42`.
331
+ * - For (2) the result is `x = 34`.
332
+ * - For (3) the result is `++x`.
333
+ * - For (4) the result is `x++`.
334
+ * - For (5) the result is `x += 1`.
335
+ * - For (6) there are two results:
336
+ * - For the definition generated by `x += 2` the result is `x += 2`
337
+ * - For the definition generated by `int y = ...` the result is
338
+ * also `x += 2`.
339
+ *
340
+ * For assignments, `node.asDefinition(_)` and `node.asExpr()` will both exist
341
+ * for the same dataflow node. However, for expression such as `x++` that
342
+ * both write to `x` and read the current value of `x`, `node.asDefinition(_)`
343
+ * will give the node corresponding to the value after the increment, and
344
+ * `node.asExpr()` will give the node corresponding to the value before the
345
+ * increment. For an example of this, consider the following:
346
+ *
347
+ * ```cpp
348
+ * sink(x++);
349
+ * ```
350
+ * in the above program, there will not be flow from a node `n` such that
351
+ * `n.asDefinition(_) instanceof IncrementOperation` to the argument of `sink`
352
+ * since the value passed to `sink` is the value before to the increment.
353
+ * However, there will be dataflow from a node `n` such that
354
+ * `n.asExpr() instanceof IncrementOperation` since the result of evaluating
355
+ * the expression `x++` is passed to `sink`.
356
+ *
357
+ * If `uncertain = false` then the definition is guaranteed to overwrite
358
+ * the entire buffer pointed to by the destination address of the definition.
359
+ * Otherwise, `uncertain = true`.
360
+ *
361
+ * For example, the write `int x; x = 42;` is guaranteed to overwrite all the
362
+ * bytes allocated to `x`, while the assignment `int p[10]; p[3] = 42;` has
363
+ * `uncertain = true` since the write will not overwrite the entire buffer
364
+ * pointed to by `p`.
365
+ */
366
+ Expr asDefinition ( boolean uncertain ) {
367
+ exists ( StoreInstruction store , Ssa:: DefinitionExt def |
318
368
store = this .asInstruction ( ) and
319
- result = asDefinitionImpl ( store )
369
+ result = asDefinitionImpl ( store ) and
370
+ Ssa:: defToNode ( this , def , _, _, _, _) and
371
+ if def .isCertain ( ) then uncertain = false else uncertain = true
320
372
)
321
373
}
322
374
375
+ /**
376
+ * Gets the definition associated with this node, if this node is a certain definition.
377
+ *
378
+ * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
379
+ */
380
+ Expr asCertainDefinition ( ) { result = this .asDefinition ( false ) }
381
+
382
+ /**
383
+ * Gets the definition associated with this node, if this node is an uncertain definition.
384
+ *
385
+ * See `Node.asDefinition/1` for a description of certain and uncertain definitions.
386
+ */
387
+ Expr asUncertainDefinition ( ) { result = this .asDefinition ( true ) }
388
+
323
389
/**
324
390
* Gets the indirect definition at a given indirection corresponding to this
325
391
* node, if any.
0 commit comments