-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathCachedStages.qll
More file actions
210 lines (198 loc) · 6.35 KB
/
CachedStages.qll
File metadata and controls
210 lines (198 loc) · 6.35 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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
/**
* INTERNAL: Do not use.
*
* The purpose of this file is to control which cached predicates belong to the same stage.
*
* Combining stages can improve performance as we are more likely to reuse shared, non-cached predicates.
*
* To make a predicate `p` belong to a stage `A`:
* - make `p` depend on `A::ref()`, and
* - make `A::backref()` depend on `p`.
*
* Since `A` is a cached module, `ref` and `backref` must be in the same stage, and the dependency
* chain above thus forces `p` to be in that stage as well.
*
* With these two predicates in a `cached module` we ensure that all the cached predicates will be in a single stage at runtime.
*
* Grouping stages can cause unnecessary computation, as a concrete query might not depend on
* all the cached predicates in a stage.
* Care should therefore be taken not to combine two stages, if it is likely that a query only depend
* on some but not all the cached predicates in the combined stage.
*/
/**
* Contains a `cached module` for each stage.
* Each `cached module` ensures that predicates that are supposed to be in the same stage, are in the same stage.
*
* Each `cached module` contain two predicates:
* The first, `ref`, always holds, and is referenced from `cached` predicates.
* The second, `backref`, contains references to the same `cached` predicates.
* The `backref` predicate starts with `1 = 1 or` to ensure that the predicate will be optimized down to a constant by the optimizer.
*/
module Stages {
/**
* The `AST` stage.
* Computes predicates based on the AST.
* These include SSA and basic-blocks.
*/
overlay[local]
cached
module AST {
/**
* Always holds.
* Ensures that a predicate is evaluated as part of the Ast stage.
*/
cached
predicate ref() { 1 = 1 }
private import semmle.python.essa.SsaDefinitions as SsaDefinitions
private import semmle.python.essa.SsaCompute as SsaCompute
private import semmle.python.essa.Essa as Essa
private import semmle.python.Module as PyModule
private import semmle.python.Exprs as Exprs
private import semmle.python.AstExtended as AstExtended
private import semmle.python.Flow as PyFlow
/**
* DONT USE!
* Contains references to each predicate that use the above `ref` predicate.
*/
cached
predicate backref() {
1 = 1
or
SsaDefinitions::SsaSource::method_call_refinement(_, _, _)
or
SsaCompute::SsaDefinitions::reachesEndOfBlock(_, _, _, _)
or
exists(any(Essa::PhiFunction p).getInput(_))
or
exists(PyModule::moduleNameFromFile(_))
or
exists(any(Exprs::Expr e).toString())
or
exists(any(AstExtended::AstNode n).getLocation())
or
exists(any(AstExtended::AstNode n).getAChildNode())
or
exists(any(AstExtended::AstNode n).getParentNode())
or
exists(any(AstExtended::AstNode n).getAFlowNode())
or
exists(any(PyFlow::BasicBlock b).getImmediateDominator())
or
exists(any(PyFlow::BasicBlock b).getScope())
or
any(PyFlow::BasicBlock b).strictlyDominates(_)
or
any(PyFlow::BasicBlock b).strictlyReaches(_)
or
exists(any(PyFlow::BasicBlock b).getASuccessor())
or
exists(any(PyFlow::ControlFlowNode b).getScope())
or
exists(PyFlow::DefinitionNode b)
or
exists(any(PyFlow::SequenceNode n).getElement(_))
or
exists(any(PyFlow::ControlFlowNode c).toString())
}
}
/**
* The `TypeTracking` stage.
*/
cached
module TypeTracking {
/**
* Always holds.
* Ensures that a predicate is evaluated as part of the Ast stage.
*/
cached
predicate ref() { 1 = 1 }
private import semmle.python.dataflow.new.DataFlow::DataFlow as NewDataFlow
private import semmle.python.dataflow.new.internal.TypeTrackingImpl as TypeTrackingImpl
private import semmle.python.ApiGraphs::API as API
/**
* DONT USE!
* Contains references to each predicate that use the above `ref` predicate.
*/
cached
predicate backref() {
1 = 1
or
exists(TypeTrackingImpl::append(_, _))
or
exists(any(API::Node n).getAMember().getAValueReachableFromSource())
}
}
/**
* The points-to stage.
*/
cached
module PointsTo {
/**
* Always holds.
* Ensures that a predicate is evaluated as part of the points-to stage.
*/
cached
predicate ref() { 1 = 1 }
private import semmle.python.pointsto.Base as PointsToBase
private import semmle.python.types.Object as TypeObject
private import semmle.python.objects.TObject as TObject
private import semmle.python.objects.ObjectInternal as ObjectInternal
// have to alias since this module is also called PointsTo
private import semmle.python.pointsto.PointsTo as RealPointsTo
/**
* DONT USE!
* Contains references to each predicate that use the above `ref` predicate.
*/
cached
predicate backref() {
1 = 1
or
PointsToBase::BaseFlow::scope_entry_value_transfer_from_earlier(_, _, _, _)
or
exists(TypeObject::Object a)
or
exists(TObject::TObject f)
or
exists(any(ObjectInternal::ObjectInternal o).toString())
or
RealPointsTo::AttributePointsTo::variableAttributePointsTo(_, _, _, _, _)
}
}
/**
* The `dataflow` stage.
*/
cached
module DataFlow {
/**
* Always holds.
* Ensures that a predicate is evaluated as part of the DataFlow stage.
*/
overlay[local]
cached
predicate ref() { 1 = 1 }
private import semmle.python.dataflow.new.internal.DataFlowPublic as DataFlowPublic
private import semmle.python.dataflow.new.internal.DataFlowDispatch as DataFlowDispatch
private import semmle.python.dataflow.new.internal.LocalSources as LocalSources
private import semmle.python.internal.Awaited as Awaited
/**
* DONT USE!
* Contains references to each predicate that use the above `ref` predicate.
*/
cached
predicate backref() {
1 = 1
or
exists(any(DataFlowPublic::Node node).toString())
or
exists(any(DataFlowPublic::Node node).getLocation())
or
DataFlowDispatch::resolveCall(_, _, _)
or
DataFlowDispatch::getCallArg(_, _, _, _, _)
or
any(LocalSources::LocalSourceNode n).flowsTo(_)
or
exists(Awaited::awaited(_))
}
}
}