Skip to content

Commit e2f79d8

Browse files
authored
Python: Fix several bad getScope joins
It seems the optimiser has started getting the wrong end of the stick whenever we write `foo.getScope() = bar.getScope()` for some expressions `foo` and `bar`. This lead to things like ``` (196s) Tuple counts for Definitions::ModuleVariable::global_variable_callnode#ff/2@5ab278 after 2m33s: 2952757013 ~0% {2} r1 = JOIN Definitions::ModuleVariable::global_variable_callnode#ff#shared WITH Variables::Variable::getScope_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1 'result' 495693 ~0% {2} r2 = JOIN r1 WITH Variables::GlobalVariable#class#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result' 453589 ~0% {2} r3 = JOIN r2 WITH Definitions::ModuleVariable#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result' return r3 ``` and ``` (315s) Tuple counts for Definitions::SsaSourceVariable::getAUse_dispred#ff/2@a39328 after 1m57s: ... 1785275 ~3% {2} r24 = Definitions::ModuleVariable::global_variable_callnode#ff#shared UNION Definitions::SsaSourceVariable::getAUse_dispred#ff#shared 3008614987 ~0% {2} r25 = JOIN r24 WITH Variables::Variable::getScope_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1 'result' 127 ~1% {2} r26 = JOIN r25 WITH Definitions::NonLocalVariable#class#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result' 127 ~1% {2} r27 = JOIN r26 WITH Variables::LocalVariable#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result' ... ``` (Note the timings: 2m33s and 1m57s.) Now we have the much more reasonable ``` (38s) Tuple counts for Definitions::ModuleVariable::global_variable_callnode#ff/2@c53031 after 42ms: 453589 ~0% {2} r1 = JOIN Definitions::ModuleVariable::global_variable_callnode#ff#shared WITH Definitions::ModuleVariable::scope_as_global_variable#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1 'result' return r1 ``` and ``` (46s) Tuple counts for Definitions::SsaSourceVariable::getAUse_dispred#ff/2@4b19de after 375ms: ... ```
1 parent 24000a5 commit e2f79d8

File tree

1 file changed

+11
-8
lines changed

1 file changed

+11
-8
lines changed

python/ql/lib/semmle/python/essa/Definitions.qll

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -152,17 +152,17 @@ class NonLocalVariable extends SsaSourceVariable {
152152
}
153153

154154
override ControlFlowNode getAnImplicitUse() {
155-
result.(CallNode).getScope().getScope*() = this.(LocalVariable).getScope()
155+
result.(CallNode).getScope().getScope*() = this.scope_as_local_variable()
156156
}
157157

158158
override ControlFlowNode getScopeEntryDefinition() {
159159
exists(Function f |
160-
f.getScope+() = this.(LocalVariable).getScope() and
160+
f.getScope+() = this.scope_as_local_variable() and
161161
f.getEntryNode() = result
162162
)
163163
or
164164
not this.(LocalVariable).isParameter() and
165-
this.(LocalVariable).getScope().getEntryNode() = result
165+
this.scope_as_local_variable().getEntryNode() = result
166166
}
167167

168168
pragma[noinline]
@@ -215,12 +215,15 @@ class ModuleVariable extends SsaSourceVariable {
215215
)
216216
}
217217

218+
pragma[nomagic]
219+
private Scope scope_as_global_variable() { result = this.(GlobalVariable).getScope() }
220+
218221
pragma[noinline]
219-
CallNode global_variable_callnode() { result.getScope() = this.(GlobalVariable).getScope() }
222+
CallNode global_variable_callnode() { result.getScope() = this.scope_as_global_variable() }
220223

221224
pragma[noinline]
222225
ImportMemberNode global_variable_import() {
223-
result.getScope() = this.(GlobalVariable).getScope() and
226+
result.getScope() = this.scope_as_global_variable() and
224227
import_from_dot_in_init(result.getModule(this.getName()))
225228
}
226229

@@ -250,7 +253,7 @@ class ModuleVariable extends SsaSourceVariable {
250253
override ControlFlowNode getScopeEntryDefinition() {
251254
exists(Scope s | s.getEntryNode() = result |
252255
/* Module entry point */
253-
this.(GlobalVariable).getScope() = s
256+
this.scope_as_global_variable() = s
254257
or
255258
/* For implicit use of __metaclass__ when constructing class */
256259
class_with_global_metaclass(s, this)
@@ -286,13 +289,13 @@ class EscapingGlobalVariable extends ModuleVariable {
286289
override ControlFlowNode getAnImplicitUse() {
287290
result = ModuleVariable.super.getAnImplicitUse()
288291
or
289-
result.(CallNode).getScope().getScope+() = this.(GlobalVariable).getScope()
292+
result.(CallNode).getScope().getScope+() = this.scope_as_global_variable()
290293
or
291294
result = this.innerScope().getANormalExit()
292295
}
293296

294297
private Scope innerScope() {
295-
result.getScope+() = this.(GlobalVariable).getScope() and
298+
result.getScope+() = this.scope_as_global_variable() and
296299
not result instanceof ImportTimeScope
297300
}
298301

0 commit comments

Comments
 (0)