forked from github/codeql
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPaths.qll
More file actions
87 lines (75 loc) · 2.93 KB
/
Paths.qll
File metadata and controls
87 lines (75 loc) · 2.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
/**
* This library provides predicates for reasoning about the set of all paths
* through a callable.
*/
import java
import semmle.code.java.dispatch.VirtualDispatch
/**
* A configuration to define an "action". The member predicates
* `callableAlwaysPerformsAction` and `callAlwaysPerformsAction` then gives all
* the callables and calls that always performs an action taking
* inter-procedural flow into account.
*/
abstract class ActionConfiguration extends string {
bindingset[this]
ActionConfiguration() { any() }
/** Holds if `node` is an action. */
abstract predicate isAction(ControlFlowNode node);
/** Holds if every path through `callable` goes through at least one action node. */
final predicate callableAlwaysPerformsAction(Callable callable) {
callableAlwaysPerformsAction(callable, this)
}
/** Holds if every path through `call` goes through at least one action node. */
final predicate callAlwaysPerformsAction(Call call) { callAlwaysPerformsAction(call, this) }
}
/** Gets a `BasicBlock` that contains an action. */
private BasicBlock actionBlock(ActionConfiguration conf) {
exists(ControlFlowNode node | result = node.getBasicBlock() |
conf.isAction(node) or
callAlwaysPerformsAction(node, conf)
)
}
/** Holds if every path through `call` goes through at least one action node. */
private predicate callAlwaysPerformsAction(Call call, ActionConfiguration conf) {
forex(Callable callable | callable = viableCallable(call) |
callableAlwaysPerformsAction(callable, conf)
)
}
/** Holds if an action dominates the exit of the callable. */
private predicate actionDominatesExit(Callable callable, ActionConfiguration conf) {
exists(BasicBlock exit |
exit.getLastNode() = callable and
actionBlock(conf).bbDominates(exit)
)
}
/** Gets a `BasicBlock` that contains an action that does not dominate the exit. */
private BasicBlock nonDominatingActionBlock(ActionConfiguration conf) {
exists(BasicBlock exit |
result = actionBlock(conf) and
exit.getLastNode() = result.getEnclosingCallable() and
not result.bbDominates(exit)
)
}
private class JoinBlock extends BasicBlock {
JoinBlock() { 2 <= strictcount(this.getABBPredecessor()) }
}
/**
* Holds if `bb` is a block that is collectively dominated by a set of one or
* more actions that individually does not dominate the exit.
*/
private predicate postActionBlock(BasicBlock bb, ActionConfiguration conf) {
bb = nonDominatingActionBlock(conf)
or
if bb instanceof JoinBlock
then forall(BasicBlock pred | pred = bb.getABBPredecessor() | postActionBlock(pred, conf))
else postActionBlock(bb.getABBPredecessor(), conf)
}
/** Holds if every path through `callable` goes through at least one action node. */
private predicate callableAlwaysPerformsAction(Callable callable, ActionConfiguration conf) {
actionDominatesExit(callable, conf)
or
exists(BasicBlock exit |
exit.getLastNode() = callable and
postActionBlock(exit, conf)
)
}