mirror of
https://github.com/github/codeql.git
synced 2025-12-20 18:56:32 +01:00
C++: Bring back StackVariableReachability.qll
This is now a copy of `LocalScopeVariableReachability.qll`, just with `s/LocalScopeVariable/StackVariable/g`. It can be used as a drop-in replacement since the `LocalScopeVariableReachability.qll` library implementation was already restricted to `SemanticStackVariable`.
This commit is contained in:
@@ -1,11 +1,24 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariableReachability` instead.
|
||||
*
|
||||
* A reachability analysis for control-flow nodes involving stack variables.
|
||||
* This defines sources, sinks, and any other configurable aspect of the
|
||||
* analysis. Multiple analyses can coexist. To create an analysis, extend this
|
||||
* class with a subclass whose characteristic predicate is a unique singleton
|
||||
* string. For example, write
|
||||
*
|
||||
* ```
|
||||
* class MyAnalysisConfiguration extends StackVariableReachability {
|
||||
* MyAnalysisConfiguration() { this = "MyAnalysisConfiguration" }
|
||||
* // Override `isSource` and `isSink`.
|
||||
* // Override `isBarrier`.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* Then, to query whether there is flow between some source and sink, call the
|
||||
* `reaches` predicate on an instance of `MyAnalysisConfiguration`.
|
||||
*/
|
||||
abstract deprecated class StackVariableReachability extends string {
|
||||
abstract class StackVariableReachability extends string {
|
||||
bindingset[this]
|
||||
StackVariableReachability() { length() >= 0 }
|
||||
|
||||
@@ -24,13 +37,13 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
* uses basic blocks internally for better performance:
|
||||
*
|
||||
* ```
|
||||
* predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* reachesImpl(source, v, sink)
|
||||
* and
|
||||
* isSink(sink, v)
|
||||
* }
|
||||
*
|
||||
* predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* sink = source.getASuccessor() and isSource(source, v)
|
||||
* or
|
||||
* exists(ControlFlowNode mid | reachesImpl(source, v, mid) |
|
||||
@@ -44,7 +57,7 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
* In addition to using a better performing implementation, this analysis
|
||||
* accounts for loops where the condition is provably true upon entry.
|
||||
*/
|
||||
predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
/*
|
||||
* Implementation detail: the predicates in this class are a generalization of
|
||||
* those in DefinitionsAndUses.qll, and should be kept in sync.
|
||||
@@ -71,7 +84,8 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
}
|
||||
|
||||
private predicate bbSuccessorEntryReaches(
|
||||
BasicBlock bb, StackVariable v, ControlFlowNode node, boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
||||
bbSuccessorEntryReachesLoopInvariant(bb, succ, skipsFirstLoopAlwaysTrueUponEntry,
|
||||
@@ -85,11 +99,22 @@ abstract deprecated class StackVariableReachability extends string {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate bbEntryReachesLocally(BasicBlock bb, StackVariable v, ControlFlowNode node) {
|
||||
exists(int n | node = bb.getNode(n) and isSink(node, v) |
|
||||
not exists(int m | m < n | isBarrier(bb.getNode(m), v))
|
||||
private predicate bbEntryReachesLocally(
|
||||
BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
||||
) {
|
||||
exists(int n |
|
||||
node = bb.getNode(n) and
|
||||
isSink(node, v)
|
||||
|
|
||||
not exists(this.firstBarrierIndexIn(bb, v))
|
||||
or
|
||||
n <= this.firstBarrierIndexIn(bb, v)
|
||||
)
|
||||
}
|
||||
|
||||
private int firstBarrierIndexIn(BasicBlock bb, SemanticStackVariable v) {
|
||||
result = min(int m | isBarrier(bb.getNode(m), v))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -113,26 +138,32 @@ private predicate bbLoopEntryConditionAlwaysTrueAt(BasicBlock bb, int i, Control
|
||||
}
|
||||
|
||||
/**
|
||||
* Basic block `pred` ends with a condition belonging to a loop, and that
|
||||
* condition is provably true upon entry. Basic block `succ` is a successor
|
||||
* of `pred`, and `skipsLoop` indicates whether `succ` is the false-successor
|
||||
* of `pred`.
|
||||
* Basic block `pred` contains all or part of the condition belonging to a loop,
|
||||
* and there is an edge from `pred` to `succ` that concludes the condition.
|
||||
* If the edge corrseponds with the loop condition being found to be `true`, then
|
||||
* `skipsLoop` is `false`. Otherwise the edge corresponds with the loop condition
|
||||
* being found to be `false` and `skipsLoop` is `true`. Non-concluding edges
|
||||
* within a complex loop condition are not matched by this predicate.
|
||||
*/
|
||||
private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
|
||||
BasicBlock pred, BasicBlock succ, boolean skipsLoop
|
||||
) {
|
||||
succ = pred.getASuccessor() and
|
||||
exists(ControlFlowNode last |
|
||||
last = pred.getEnd() and
|
||||
loopConditionAlwaysTrueUponEntry(_, last) and
|
||||
if succ = pred.getAFalseSuccessor() then skipsLoop = true else skipsLoop = false
|
||||
exists(Expr cond |
|
||||
loopConditionAlwaysTrueUponEntry(_, cond) and
|
||||
cond.getAChild*() = pred.getEnd() and
|
||||
succ = pred.getASuccessor() and
|
||||
not cond.getAChild*() = succ.getStart() and
|
||||
(
|
||||
succ = pred.getAFalseSuccessor() and
|
||||
skipsLoop = true
|
||||
or
|
||||
succ = pred.getATrueSuccessor() and
|
||||
skipsLoop = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use the corresponding predicate in
|
||||
* `LocalScopeVariableReachability` instead.
|
||||
*
|
||||
* Loop invariant for `bbSuccessorEntryReaches`:
|
||||
*
|
||||
* - `succ` is a successor of `pred`.
|
||||
@@ -146,7 +177,7 @@ private predicate bbLoopConditionAlwaysTrueUponEntrySuccessor(
|
||||
* is provably true upon entry, then `succ` is not allowed to skip
|
||||
* that loop (`succSkipsFirstLoopAlwaysTrueUponEntry = false`).
|
||||
*/
|
||||
deprecated predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
BasicBlock pred, BasicBlock succ, boolean predSkipsFirstLoopAlwaysTrueUponEntry,
|
||||
boolean succSkipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
@@ -162,7 +193,7 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
// The edge from `pred` to `succ` is _not_ from a loop condition provably
|
||||
// true upon entry, so the values of `predSkipsFirstLoopAlwaysTrueUponEntry`
|
||||
// and `succSkipsFirstLoopAlwaysTrueUponEntry` must be the same.
|
||||
not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, _, _) and
|
||||
not bbLoopConditionAlwaysTrueUponEntrySuccessor(pred, succ, _) and
|
||||
succSkipsFirstLoopAlwaysTrueUponEntry = predSkipsFirstLoopAlwaysTrueUponEntry and
|
||||
// Moreover, if `pred` contains the entry point of a loop where the
|
||||
// condition is provably true upon entry, then `succ` is not allowed
|
||||
@@ -176,13 +207,16 @@ deprecated predicate bbSuccessorEntryReachesLoopInvariant(
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariableReachabilityWithReassignment` instead.
|
||||
*
|
||||
* Reachability analysis for control-flow nodes involving stack variables.
|
||||
* Unlike `StackVariableReachability`, this analysis takes variable
|
||||
* reassignments into account.
|
||||
*
|
||||
* This class is used like `StackVariableReachability`, except that
|
||||
* subclasses should override `isSourceActual` and `isSinkActual` instead of
|
||||
* `isSource` and `isSink`, and that there is a `reachesTo` predicate in
|
||||
* addition to `reaches`.
|
||||
*/
|
||||
abstract deprecated class StackVariableReachabilityWithReassignment extends StackVariableReachability {
|
||||
abstract class StackVariableReachabilityWithReassignment extends StackVariableReachability {
|
||||
bindingset[this]
|
||||
StackVariableReachabilityWithReassignment() { length() >= 0 }
|
||||
|
||||
@@ -199,19 +233,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
* performance:
|
||||
*
|
||||
* ```
|
||||
* predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* reachesImpl(source, v, sink)
|
||||
* and
|
||||
* isSinkActual(sink, v)
|
||||
* }
|
||||
*
|
||||
* predicate reachesImpl(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
* predicate reachesImpl(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
* isSourceActual(source, v)
|
||||
* and
|
||||
* (
|
||||
* sink = source.getASuccessor()
|
||||
* or
|
||||
* exists(ControlFlowNode mid, StackVariable v0 | reachesImpl(source, v0, mid) |
|
||||
* exists(ControlFlowNode mid, SemanticStackVariable v0 | reachesImpl(source, v0, mid) |
|
||||
* // ordinary successor
|
||||
* not isBarrier(mid, v) and
|
||||
* sink = mid.getASuccessor() and
|
||||
@@ -228,7 +262,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
* In addition to using a better performing implementation, this analysis
|
||||
* accounts for loops where the condition is provably true upon entry.
|
||||
*/
|
||||
override predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
override predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
reachesTo(source, v, sink, _)
|
||||
}
|
||||
|
||||
@@ -236,7 +270,7 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
* As `reaches`, but also specifies the last variable it was reassigned to (`v0`).
|
||||
*/
|
||||
predicate reachesTo(
|
||||
ControlFlowNode source, StackVariable v, ControlFlowNode sink, StackVariable v0
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink, SemanticStackVariable v0
|
||||
) {
|
||||
exists(ControlFlowNode def |
|
||||
actualSourceReaches(source, v, def, v0) and
|
||||
@@ -246,17 +280,19 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
}
|
||||
|
||||
private predicate actualSourceReaches(
|
||||
ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
||||
) {
|
||||
isSourceActual(source, v) and def = source and v0 = v
|
||||
or
|
||||
exists(ControlFlowNode source1, StackVariable v1 | actualSourceReaches(source, v, source1, v1) |
|
||||
exists(ControlFlowNode source1, SemanticStackVariable v1 |
|
||||
actualSourceReaches(source, v, source1, v1)
|
||||
|
|
||||
reassignment(source1, v1, def, v0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate reassignment(
|
||||
ControlFlowNode source, StackVariable v, ControlFlowNode def, StackVariable v0
|
||||
ControlFlowNode source, SemanticStackVariable v, ControlFlowNode def, SemanticStackVariable v0
|
||||
) {
|
||||
StackVariableReachability.super.reaches(source, v, def) and
|
||||
exprDefinition(v0, def, v.getAnAccess())
|
||||
@@ -278,13 +314,12 @@ abstract deprecated class StackVariableReachabilityWithReassignment extends Stac
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: use `LocalScopeVariableReachabilityExt` instead.
|
||||
*
|
||||
* Same as `StackVariableReachability`, but `isBarrier` works on control-flow
|
||||
* edges rather than nodes and is therefore parameterized by the original
|
||||
* source node as well.
|
||||
* source node as well. Otherwise, this class is used like
|
||||
* `StackVariableReachability`.
|
||||
*/
|
||||
abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
abstract class StackVariableReachabilityExt extends string {
|
||||
bindingset[this]
|
||||
StackVariableReachabilityExt() { length() >= 0 }
|
||||
|
||||
@@ -300,7 +335,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
);
|
||||
|
||||
/** See `StackVariableReachability.reaches`. */
|
||||
predicate reaches(ControlFlowNode source, StackVariable v, ControlFlowNode sink) {
|
||||
predicate reaches(ControlFlowNode source, SemanticStackVariable v, ControlFlowNode sink) {
|
||||
exists(BasicBlock bb, int i |
|
||||
isSource(source, v) and
|
||||
bb.getNode(i) = source and
|
||||
@@ -321,7 +356,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
}
|
||||
|
||||
private predicate bbSuccessorEntryReaches(
|
||||
ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node,
|
||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node,
|
||||
boolean skipsFirstLoopAlwaysTrueUponEntry
|
||||
) {
|
||||
exists(BasicBlock succ, boolean succSkipsFirstLoopAlwaysTrueUponEntry |
|
||||
@@ -338,7 +373,7 @@ abstract deprecated class StackVariableReachabilityExt extends string {
|
||||
}
|
||||
|
||||
private predicate bbEntryReachesLocally(
|
||||
ControlFlowNode source, BasicBlock bb, StackVariable v, ControlFlowNode node
|
||||
ControlFlowNode source, BasicBlock bb, SemanticStackVariable v, ControlFlowNode node
|
||||
) {
|
||||
isSource(source, v) and
|
||||
exists(int n | node = bb.getNode(n) and isSink(node, v) |
|
||||
|
||||
Reference in New Issue
Block a user