mirror of
https://github.com/github/codeql.git
synced 2026-02-20 17:03:41 +01:00
128 lines
4.8 KiB
Plaintext
128 lines
4.8 KiB
Plaintext
/**
|
|
* Provides a library for reasoning about control flow at the granularity of
|
|
* individual nodes in the control-flow graph.
|
|
*/
|
|
|
|
import cpp
|
|
import BasicBlocks
|
|
private import semmle.code.cpp.controlflow.internal.ConstantExprs
|
|
private import semmle.code.cpp.controlflow.internal.CFG
|
|
|
|
/**
|
|
* A control-flow node is either a statement or an expression; in addition,
|
|
* functions are control-flow nodes representing the exit point of the
|
|
* function. The graph represents one possible evaluation order out of all the
|
|
* ones the compiler might have picked.
|
|
*
|
|
* Control-flow nodes have successors and predecessors at the expression level,
|
|
* so control flow is accurately represented in expressions as well as between
|
|
* statements. Statements and initializers precede their contained expressions,
|
|
* and expressions deeper in the tree precede those higher up; for example, the
|
|
* statement `x = y + 1` gets a control-flow graph that looks like
|
|
*
|
|
* ```
|
|
* ExprStmt -> y -> 1 -> (+) -> x -> (=)
|
|
* ```
|
|
*
|
|
* The first control-flow node in a function is the body of the function (a
|
|
* block), and the last is the function itself, which is used to represent the
|
|
* exit point.
|
|
*
|
|
* Each `throw` expression or `Handler` has a path (along any necessary
|
|
* destructor calls) to its nearest enclosing `Handler` within the same
|
|
* function, or to the exit point of the function if there is no such
|
|
* `Handler`. There are no edges from function calls to `Handler`s.
|
|
*/
|
|
class ControlFlowNode extends Locatable, ControlFlowNodeBase {
|
|
/** Gets a direct successor of this control-flow node, if any. */
|
|
ControlFlowNode getASuccessor() { successors_adapted(this, result) }
|
|
|
|
/** Gets a direct predecessor of this control-flow node, if any. */
|
|
ControlFlowNode getAPredecessor() { this = result.getASuccessor() }
|
|
|
|
/** Gets the function containing this control-flow node. */
|
|
Function getControlFlowScope() {
|
|
none() // overridden in subclasses
|
|
}
|
|
|
|
/** Gets the smallest statement containing this control-flow node. */
|
|
Stmt getEnclosingStmt() {
|
|
none() // overridden in subclasses
|
|
}
|
|
|
|
/**
|
|
* Holds if this node is the top-level expression of a conditional statement,
|
|
* meaning that `this.getATrueSuccessor()` or `this.getAFalseSuccessor()`
|
|
* will have a result.
|
|
*/
|
|
predicate isCondition() {
|
|
exists(this.getATrueSuccessor()) or
|
|
exists(this.getAFalseSuccessor())
|
|
}
|
|
|
|
/**
|
|
* Gets a node such that the control-flow edge `(this, result)` may be
|
|
* taken when this expression is true.
|
|
*/
|
|
ControlFlowNode getATrueSuccessor() {
|
|
qlCfgTrueSuccessor(this, result) and
|
|
result = this.getASuccessor()
|
|
}
|
|
|
|
/**
|
|
* Gets a node such that the control-flow edge `(this, result)` may be
|
|
* taken when this expression is false.
|
|
*/
|
|
ControlFlowNode getAFalseSuccessor() {
|
|
qlCfgFalseSuccessor(this, result) and
|
|
result = this.getASuccessor()
|
|
}
|
|
|
|
/** Gets the `BasicBlock` containing this control-flow node. */
|
|
BasicBlock getBasicBlock() { result.getANode() = this }
|
|
}
|
|
|
|
import ControlFlowGraphPublic
|
|
|
|
/**
|
|
* An element that is convertible to `ControlFlowNode`. This class is similar
|
|
* to `ControlFlowNode` except that is has no member predicates apart from
|
|
* `toString`.
|
|
*
|
|
* This class can be used as base class for classes that want to inherit the
|
|
* extent of `ControlFlowNode` without inheriting its public member predicates.
|
|
*/
|
|
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
|
|
|
|
/**
|
|
* An abstract class that can be extended to add additional edges to the
|
|
* control-flow graph. Instances of this class correspond to the source nodes
|
|
* of such edges, and the predicate `getAnEdgeTarget` should be overridden to
|
|
* produce the target nodes of each source.
|
|
*
|
|
* Changing the control-flow graph in some queries and not others can be
|
|
* expensive in execution time and disk space. Most cached predicates in the
|
|
* library depend on the control-flow graph, so these predicates will be
|
|
* computed and cached for each variation of the control-flow graph
|
|
* that is used.
|
|
*
|
|
* Edges added by this class will still be removed by the library if they
|
|
* appear to be unreachable. See the documentation on `ControlFlowNode` for
|
|
* more information about the control-flow graph.
|
|
*/
|
|
abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase {
|
|
/** Gets a target node of this edge, where the source node is `this`. */
|
|
abstract ControlFlowNodeBase getAnEdgeTarget();
|
|
}
|
|
|
|
/**
|
|
* Holds if there is a control-flow edge from `source` to `target` in either
|
|
* the extractor-generated control-flow graph or in a subclass of
|
|
* `AdditionalControlFlowEdge`. Use this relation instead of `qlCFGSuccessor`.
|
|
*/
|
|
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
|
|
qlCfgSuccessor(source, target)
|
|
or
|
|
source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target
|
|
}
|