Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* Provides a library for reasoning about control flow at the granularity of basic blocks.
* This is usually much more efficient than reasoning directly at the level of `ControlFlowNode`s.
*/

import cpp
private import internal.PrimitiveBasicBlocks
private import internal.ConstantExprs
Expand Down Expand Up @@ -148,22 +153,37 @@ predicate bb_successor = bb_successor_cached/2;
class BasicBlock extends ControlFlowNodeBase {
BasicBlock() { basic_block_entry_node(this) }

/** Holds if this basic block contains `node`. */
predicate contains(ControlFlowNode node) { basic_block_member(node, this, _) }

/** Gets the `ControlFlowNode` at position `pos` in this basic block. */
ControlFlowNode getNode(int pos) { basic_block_member(result, this, pos) }

/** Gets a `ControlFlowNode` in this basic block. */
ControlFlowNode getANode() { basic_block_member(result, this, _) }

/** Gets a `BasicBlock` that is a direct successor of this basic block. */
BasicBlock getASuccessor() { bb_successor(this, result) }

/** Gets a `BasicBlock` that is a direct predecessor of this basic block. */
BasicBlock getAPredecessor() { bb_successor(result, this) }

/**
* Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken
* when the outgoing edge of this basic block is an expression that is true.
*/
BasicBlock getATrueSuccessor() { result.getStart() = this.getEnd().getATrueSuccessor() }

/**
* Gets a `BasicBlock` such that the control-flow edge `(this, result)` may be taken
* when the outgoing edge of this basic block is an expression that is false.
*/
BasicBlock getAFalseSuccessor() { result.getStart() = this.getEnd().getAFalseSuccessor() }

/** Gets the final `ControlFlowNode` of this basic block. */
ControlFlowNode getEnd() { basic_block_member(result, this, bb_length(this) - 1) }

/** Gets the first `ControlFlowNode` of this basic block. */
ControlFlowNode getStart() { result = this }

/** Gets the number of `ControlFlowNode`s in this basic block. */
Expand Down Expand Up @@ -192,6 +212,7 @@ class BasicBlock extends ControlFlowNodeBase {
this.getEnd().getLocation().hasLocationInfo(endf, _, _, endl, endc)
}

/** Gets the function containing this basic block. */
Function getEnclosingFunction() { result = this.getStart().getControlFlowScope() }

/**
Expand Down
16 changes: 16 additions & 0 deletions cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/**
* 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
Expand Down Expand Up @@ -29,8 +34,10 @@ private import semmle.code.cpp.controlflow.internal.CFG
* `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. */
Expand Down Expand Up @@ -71,6 +78,7 @@ class ControlFlowNode extends Locatable, ControlFlowNodeBase {
result = getASuccessor()
}

/** Gets the `BasicBlock` containing this control-flow node. */
BasicBlock getBasicBlock() { result.getANode() = this }
}

Expand All @@ -86,10 +94,18 @@ import ControlFlowGraphPublic
*/
class ControlFlowNodeBase extends ElementBase, @cfgnode { }

/**
* Holds when `n2` is a control-flow node such that the control-flow
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
*/
predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
qlCFGTrueSuccessor(n1, n2)
}

/**
* Holds when `n2` is a control-flow node such that the control-flow
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
*/
predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
qlCFGFalseSuccessor(n1, n2)
}
Expand Down
20 changes: 20 additions & 0 deletions cpp/ql/src/semmle/code/cpp/controlflow/Dataflow.qll
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,25 @@ import Dereferenced
abstract class DataflowAnnotation extends string {
DataflowAnnotation() { this = "pointer-null" or this = "pointer-valid" }

/** Holds if this annotation is the default annotation. */
abstract predicate isDefault();

/** Holds if this annotation is generated when analyzing expression `e`. */
abstract predicate generatedOn(Expr e);

/**
* Holds if this annotation is generated for the variable `v` when
* the control-flow edge `(src, dest)` is taken.
*/
abstract predicate generatedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest);

/**
* Holds if this annotation is removed for the variable `v` when
* the control-flow edge `(src, dest)` is taken.
*/
abstract predicate killedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest);

/** Holds if expression `e` is given this annotation. */
predicate marks(Expr e) {
this.generatedOn(e) and reachable(e)
or
Expand All @@ -31,6 +42,7 @@ abstract class DataflowAnnotation extends string {
exists(LocalScopeVariable v | this.marks(v, e) and e = v.getAnAccess())
}

/** Holds if the variable `v` accessed in control-flow node `n` is given this annotation. */
predicate marks(LocalScopeVariable v, ControlFlowNode n) {
v.getAnAccess().getEnclosingFunction().getBlock() = n and
this.isDefault()
Expand All @@ -57,13 +69,21 @@ abstract class DataflowAnnotation extends string {
)
}

/**
* Holds if the variable `v` preserves this annotation when the control-flow
* edge `(src, dest)` is taken.
*/
predicate preservedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) {
this.marks(v, src) and
src.getASuccessor() = dest and
not v.getInitializer() = dest and
not v.getAnAssignment() = src
}

/**
* Holds if the variable `v` is assigned this annotation when `src` is an assignment
* expression that assigns to `v` and the control-flow edge `(src, dest)` is taken.
*/
predicate assignedBy(LocalScopeVariable v, ControlFlowNode src, ControlFlowNode dest) {
this.marks(src.(AssignExpr).getRValue()) and
src = v.getAnAssignment() and
Expand Down