Skip to content

Commit 66e8b2d

Browse files
committed
C++: Add an 'asDefinition' overload to check if a definition is certain or not.
1 parent 40903a9 commit 66e8b2d

File tree

1 file changed

+69
-3
lines changed

1 file changed

+69
-3
lines changed

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

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,13 +313,79 @@ class Node extends TIRDataFlowNode {
313313
* `n.asExpr() instanceof IncrementOperation` since the result of evaluating
314314
* the expression `x++` is passed to `sink`.
315315
*/
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 |
318368
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
320372
)
321373
}
322374

375+
/**
376+
* Gets the definition associated with this node, if this node is a certain definition.
377+
*
378+
* See `Node.asDefinition` 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` for a description of certain and uncertain definitions.
386+
*/
387+
Expr asUncertainDefinition() { result = this.asDefinition(true) }
388+
323389
/**
324390
* Gets the indirect definition at a given indirection corresponding to this
325391
* node, if any.

0 commit comments

Comments
 (0)