mirror of
https://github.com/github/codeql.git
synced 2025-12-22 19:56:32 +01:00
C++: Add a new API for mapping a dataflow node to a definition. This means we can reduce duplication from 'asExpr'.
This commit is contained in:
@@ -260,6 +260,54 @@ class Node extends TIRDataFlowNode {
|
|||||||
*/
|
*/
|
||||||
Expr asDefiningArgument() { result = this.asDefiningArgument(_) }
|
Expr asDefiningArgument() { result = this.asDefiningArgument(_) }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the definition associated with this node, if any.
|
||||||
|
*
|
||||||
|
* For example, consider the following example
|
||||||
|
* ```cpp
|
||||||
|
* int x = 42; // 1
|
||||||
|
* x = 34; // 2
|
||||||
|
* ++x; // 3
|
||||||
|
* x++; // 4
|
||||||
|
* x += 1; // 5
|
||||||
|
* int y = x += 2; // 6
|
||||||
|
* ```
|
||||||
|
* - For (1) the result is `42`.
|
||||||
|
* - For (2) the result is `x = 34`.
|
||||||
|
* - For (3) the result is `++x`.
|
||||||
|
* - For (4) the result is `x++`.
|
||||||
|
* - For (5) the result is `x += 1`.
|
||||||
|
* - For (6) there are two results:
|
||||||
|
* - For the definition generated by `x += 2` the result is `x += 2`
|
||||||
|
* - For the definition generated by `int y = ...` the result is
|
||||||
|
* also `x += 2`
|
||||||
|
*/
|
||||||
|
Expr asDefinition() {
|
||||||
|
exists(StoreInstruction store |
|
||||||
|
store = this.asInstruction() and
|
||||||
|
result = asDefinitionImpl(store)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the indirect definition at a given indirection corresponding to this
|
||||||
|
* node, if any.
|
||||||
|
*
|
||||||
|
* See the comments on `Node.asDefinition` for examples.
|
||||||
|
*/
|
||||||
|
Expr asIndirectDefinition(int indirectionIndex) {
|
||||||
|
exists(StoreInstruction store |
|
||||||
|
this.(IndirectInstruction).hasInstructionAndIndirectionIndex(store, indirectionIndex) and
|
||||||
|
result = asDefinitionImpl(store)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the indirect definition at some indirection corresponding to this
|
||||||
|
* node, if any.
|
||||||
|
*/
|
||||||
|
Expr asIndirectDefinition() { result = this.asIndirectDefinition(_) }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
|
* Gets the argument that defines this `DefinitionByReferenceNode`, if any.
|
||||||
*
|
*
|
||||||
@@ -1142,22 +1190,6 @@ private module GetConvertedResultExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
private Expr getConvertedResultExpressionImpl0(Instruction instr) {
|
||||||
// For an expression such as `i += 2` we pretend that the generated
|
|
||||||
// `StoreInstruction` contains the result of the expression even though
|
|
||||||
// this isn't totally aligned with the C/C++ standard.
|
|
||||||
exists(TranslatedAssignOperation tao |
|
|
||||||
result = tao.getExpr() and
|
|
||||||
instr = tao.getInstruction(any(AssignmentStoreTag tag))
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// Similarly for `i++` and `++i` we pretend that the generated
|
|
||||||
// `StoreInstruction` is contains the result of the expression even though
|
|
||||||
// this isn't totally aligned with the C/C++ standard.
|
|
||||||
exists(TranslatedCrementOperation tco |
|
|
||||||
result = tco.getExpr() and
|
|
||||||
instr = tco.getInstruction(any(CrementStoreTag tag))
|
|
||||||
)
|
|
||||||
or
|
|
||||||
// IR construction inserts an additional cast to a `size_t` on the extent
|
// IR construction inserts an additional cast to a `size_t` on the extent
|
||||||
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
// of a `new[]` expression. The resulting `ConvertInstruction` doesn't have
|
||||||
// a result for `getConvertedResultExpression`. We remap this here so that
|
// a result for `getConvertedResultExpression`. We remap this here so that
|
||||||
@@ -1182,6 +1214,75 @@ private module GetConvertedResultExpression {
|
|||||||
not exists(getConvertedResultExpressionImpl0(instr)) and
|
not exists(getConvertedResultExpressionImpl0(instr)) and
|
||||||
result = instr.getConvertedResultExpression()
|
result = instr.getConvertedResultExpression()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the result for `node.asDefinition()` (when `node` is the instruction
|
||||||
|
* node that wraps `store`) in the cases where `store.getAst()` should not be
|
||||||
|
* used to define the result of `node.asDefinition()`.
|
||||||
|
*/
|
||||||
|
private Expr asDefinitionImpl0(StoreInstruction store) {
|
||||||
|
// For an expression such as `i += 2` we pretend that the generated
|
||||||
|
// `StoreInstruction` contains the result of the expression even though
|
||||||
|
// this isn't totally aligned with the C/C++ standard.
|
||||||
|
exists(TranslatedAssignOperation tao |
|
||||||
|
store = tao.getInstruction(any(AssignmentStoreTag tag)) and
|
||||||
|
result = tao.getExpr()
|
||||||
|
)
|
||||||
|
or
|
||||||
|
// Similarly for `i++` and `++i` we pretend that the generated
|
||||||
|
// `StoreInstruction` is contains the result of the expression even though
|
||||||
|
// this isn't totally aligned with the C/C++ standard.
|
||||||
|
exists(TranslatedCrementOperation tco |
|
||||||
|
store = tco.getInstruction(any(CrementStoreTag tag)) and
|
||||||
|
result = tco.getExpr()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Holds if the expression returned by `store.getAst()` should not be
|
||||||
|
* returned as the result of `node.asDefinition()` when `node` is the
|
||||||
|
* instruction node that wraps `store`.
|
||||||
|
*/
|
||||||
|
private predicate excludeAsDefinitionResult(StoreInstruction store) {
|
||||||
|
// Exclude the store to the temporary generated by a ternary expression.
|
||||||
|
exists(TranslatedConditionalExpr tce |
|
||||||
|
store = tce.getInstruction(any(ConditionValueFalseStoreTag tag))
|
||||||
|
or
|
||||||
|
store = tce.getInstruction(any(ConditionValueTrueStoreTag tag))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the expression that represents the result of `StoreInstruction` for
|
||||||
|
* dataflow purposes.
|
||||||
|
*
|
||||||
|
* For example, consider the following example
|
||||||
|
* ```cpp
|
||||||
|
* int x = 42; // 1
|
||||||
|
* x = 34; // 2
|
||||||
|
* ++x; // 3
|
||||||
|
* x++; // 4
|
||||||
|
* x += 1; // 5
|
||||||
|
* int y = x += 2; // 6
|
||||||
|
* ```
|
||||||
|
* For (1) the result is `42`.
|
||||||
|
* For (2) the result is `x = 34`.
|
||||||
|
* For (3) the result is `++x`.
|
||||||
|
* For (4) the result is `x++`.
|
||||||
|
* For (5) the result is `x += 1`.
|
||||||
|
* For (6) there are two results:
|
||||||
|
* - For the `StoreInstruction` generated by `x += 2` the result
|
||||||
|
* is `x += 2`
|
||||||
|
* - For the `StoreInstruction` generated by `int y = ...` the result
|
||||||
|
* is also `x += 2`
|
||||||
|
*/
|
||||||
|
Expr asDefinitionImpl(StoreInstruction store) {
|
||||||
|
not exists(asDefinitionImpl0(store)) and
|
||||||
|
not excludeAsDefinitionResult(store) and
|
||||||
|
result = store.getAst().(Expr).getUnconverted()
|
||||||
|
or
|
||||||
|
result = asDefinitionImpl0(store)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private import GetConvertedResultExpression
|
private import GetConvertedResultExpression
|
||||||
@@ -1947,7 +2048,12 @@ module ExprFlowCached {
|
|||||||
isIndirectBaseOfArrayAccess(n, result)
|
isIndirectBaseOfArrayAccess(n, result)
|
||||||
or
|
or
|
||||||
not isIndirectBaseOfArrayAccess(n, _) and
|
not isIndirectBaseOfArrayAccess(n, _) and
|
||||||
result = n.asExpr()
|
(
|
||||||
|
result = n.asExpr()
|
||||||
|
or
|
||||||
|
result = n.asDefinition() and
|
||||||
|
result instanceof CrementOperation
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user