Skip to content

Commit 8921620

Browse files
authored
Merge pull request #969 from markshannon/python-points-to-speed-up
Python: Refactor three predicates to improve join-order.
2 parents cd721f3 + a1820fe commit 8921620

File tree

2 files changed

+37
-12
lines changed

2 files changed

+37
-12
lines changed

python/ql/src/semmle/python/Flow.qll

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,20 @@ class BasicBlock extends @py_flow_node {
10231023
predicate likelyReachable() {
10241024
start_bb_likely_reachable(this)
10251025
}
1026+
1027+
/** Gets the `ConditionBlock`, if any, that controls this block and
1028+
* does not control any other `ConditionBlock`s that control this block.
1029+
* That is the `ConditionBlock` that is closest dominator.
1030+
*/
1031+
ConditionBlock getImmediatelyControllingBlock() {
1032+
result = this.nonControllingImmediateDominator*().getImmediateDominator()
1033+
}
1034+
1035+
private BasicBlock nonControllingImmediateDominator() {
1036+
result = this.getImmediateDominator() and
1037+
not result.(ConditionBlock).controls(this, _)
1038+
}
1039+
10261040
}
10271041

10281042
private predicate start_bb_likely_reachable(BasicBlock b) {

python/ql/src/semmle/python/pointsto/PointsTo.qll

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -447,10 +447,13 @@ module PointsTo {
447447
private module Layer {
448448

449449
/* Holds if BasicBlock `b` is reachable, given the context `context`. */
450-
predicate reachableBlock(BasicBlock b, PointsToContext context) {
451-
context.appliesToScope(b.getScope()) and
452-
forall(ConditionBlock guard |
453-
guard.controls(b, _) |
450+
predicate reachableBlock(BasicBlock b, PointsToContext context) {
451+
context.appliesToScope(b.getScope()) and not exists(ConditionBlock guard | guard.controls(b, _))
452+
or
453+
exists(ConditionBlock guard |
454+
guard = b.getImmediatelyControllingBlock() and
455+
reachableBlock(guard, context)
456+
|
454457
exists(Object value |
455458
points_to(guard.getLastNode(), context, value, _, _)
456459
|
@@ -1827,21 +1830,27 @@ module PointsTo {
18271830
)
18281831
}
18291832

1830-
pragma [noinline]
1831-
private predicate callsite_points_to_python(CallsiteRefinement def, PointsToContext context, Object value, ClassObject cls, CfgOrigin origin) {
1832-
ssa_variable_points_to(def.getInput(), context, value, cls, origin) and
1833-
exists(CallNode call, PythonSsaSourceVariable var |
1833+
/** Holds if `call`, in `context` is a call to a function that does not modify the refined variable */
1834+
private predicate call_to_safe_function(CallsiteRefinement def, PointsToContext context) {
1835+
exists(CallNode call |
18341836
call = def.getCall() and
1835-
var = def.getSourceVariable() and
18361837
context.untrackableCall(call) and
18371838
exists(PyFunctionObject modifier, Function f |
18381839
f = modifier.getFunction() and
18391840
call = get_a_call(modifier, context) and
1840-
not modifies_escaping_variable(f, var)
1841+
not modifies_escaping_variable(f, def.getSourceVariable())
18411842
)
18421843
)
18431844
}
18441845

1846+
private predicate callsite_points_to_python(CallsiteRefinement def, PointsToContext context, Object value, ClassObject cls, CfgOrigin origin) {
1847+
exists(EssaVariable input |
1848+
input = def.getInput() and
1849+
ssa_variable_points_to(input, context, value, cls, origin) and
1850+
call_to_safe_function(def, context)
1851+
)
1852+
}
1853+
18451854
private predicate modifies_escaping_variable(Function modifier, PythonSsaSourceVariable var) {
18461855
exists(var.redefinedAtCallSite()) and
18471856
modifier.getBody().contains(var.(Variable).getAStore())
@@ -2987,19 +2996,21 @@ class SuperBoundMethod extends Object {
29872996

29882997
SuperCall superObject;
29892998
string name;
2999+
ClassObject startType;
29903000

29913001
cached
29923002
SuperBoundMethod() {
29933003
exists(ControlFlowNode object |
29943004
this.(AttrNode).getObject(name) = object |
2995-
PointsTo::points_to(object, _, superObject, _, _)
3005+
PointsTo::points_to(object, _, superObject, _, _) and
3006+
startType = superObject.startType()
29963007
)
29973008
}
29983009

29993010
FunctionObject getFunction(PointsToContext ctx) {
30003011
exists(ClassList mro |
30013012
mro = PointsTo::Types::get_mro(superObject.selfType(ctx)) |
3002-
result = mro.startingAt(superObject.startType()).getTail().lookup(name)
3013+
result = mro.startingAt(startType).getTail().lookup(name)
30033014
)
30043015
}
30053016

0 commit comments

Comments
 (0)