Skip to content

Commit 58d90c7

Browse files
committed
Python: More points-to performance improvements
1 parent 7fd8d6d commit 58d90c7

File tree

2 files changed

+169
-63
lines changed

2 files changed

+169
-63
lines changed

python/ql/lib/semmle/python/pointsto/MRO.qll

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -120,16 +120,27 @@ class ClassList extends TClassList {
120120
this.getTail().contains(cls)
121121
}
122122

123+
pragma[nomagic]
123124
ClassObjectInternal findDeclaringClass(string name) {
124-
exists(ClassDecl head | head = this.getHead().getClassDeclaration() |
125-
if head.declaresAttribute(name)
126-
then result = this.getHead()
127-
else result = this.getTail().findDeclaringClass(name)
125+
exists(ClassObjectInternal head, ClassList tail, ClassDecl decl |
126+
this = Cons(head, tail) and decl = head.getClassDeclaration()
127+
|
128+
if decl.declaresAttribute(name) then result = head else result = tail.findDeclaringClass(name)
129+
)
130+
}
131+
132+
pragma[noinline]
133+
private ClassObjectInternal findDeclaringClassAttribute(string name) {
134+
result = findDeclaringClass(name) and
135+
(
136+
exists(any(Builtin b).getMember(name))
137+
or
138+
declaredAttributeVar(_, name, _)
128139
)
129140
}
130141

131142
predicate lookup(string name, ObjectInternal value, CfgOrigin origin) {
132-
exists(ClassObjectInternal decl | decl = this.findDeclaringClass(name) |
143+
exists(ClassObjectInternal decl | decl = this.findDeclaringClassAttribute(name) |
133144
Types::declaredAttribute(decl, name, value, origin)
134145
)
135146
}
@@ -252,6 +263,24 @@ private class ClassListList extends TClassListList {
252263
result = this.getTail().getItem(n - 1)
253264
}
254265

266+
/**
267+
* Same as
268+
*
269+
* ```ql
270+
* result = this.getItem(n) and n = this.length() - 1
271+
* ```
272+
*
273+
* but avoids non-linear recursion.
274+
*/
275+
ClassList getLastItem(int n) {
276+
n = 0 and this = ConsList(result, EmptyList())
277+
or
278+
exists(ClassListList tail |
279+
this = ConsList(_, tail) and
280+
result = tail.getLastItem(n - 1)
281+
)
282+
}
283+
255284
private ClassObjectInternal getAHead() {
256285
result = this.getHead().getHead()
257286
or
@@ -274,8 +303,7 @@ private class ClassListList extends TClassListList {
274303
ClassObjectInternal cls, ClassList removed_head, ClassListList removed_tail, int n
275304
) {
276305
cls = this.bestMergeCandidate() and
277-
n = this.length() - 1 and
278-
removed_head = this.getItem(n).removeHead(cls) and
306+
removed_head = this.getLastItem(n).removeHead(cls) and
279307
removed_tail = EmptyList()
280308
or
281309
removed_head = this.removedClassPartsCons1(cls, removed_tail, n).removeHead(cls)
@@ -305,33 +333,33 @@ private class ClassListList extends TClassListList {
305333
}
306334

307335
pragma[nomagic]
308-
private predicate legalMergeCandidateNonEmpty(ClassObjectInternal cls, int n, ClassList cl, int j) {
309-
this.legalMergeCandidate(cls, n + 1) and
310-
cl = this.getItem(n) and
311-
j = cl.length()
336+
private predicate legalMergeCandidateNonEmpty(
337+
ClassObjectInternal cls, ClassListList remainingList, ClassList remaining
338+
) {
339+
this.legalMergeCandidate(cls, ConsList(Cons(_, remaining), remainingList))
312340
or
313-
this.legalMergeCandidateNonEmpty(cls, n, cl, j + 1) and
314-
j >= 1 and
315-
cls != cl.getItem(j)
341+
exists(ClassObjectInternal head |
342+
this.legalMergeCandidateNonEmpty(cls, remainingList, Cons(head, remaining)) and
343+
cls != head
344+
)
316345
}
317346

318-
private predicate legalMergeCandidate(ClassObjectInternal cls, int n) {
319-
cls = this.getAHead() and n = this.length()
347+
private predicate legalMergeCandidate(ClassObjectInternal cls, ClassListList remaining) {
348+
cls = this.getAHead() and remaining = this
320349
or
321-
this.legalMergeCandidate(cls, n + 1) and
322-
this.getItem(n) = Empty()
350+
this.legalMergeCandidate(cls, ConsList(Empty(), remaining))
323351
or
324-
this.legalMergeCandidateNonEmpty(cls, n, _, 1)
352+
this.legalMergeCandidateNonEmpty(cls, remaining, Empty())
325353
}
326354

327-
predicate legalMergeCandidate(ClassObjectInternal cls) { this.legalMergeCandidate(cls, 0) }
355+
pragma[noinline]
356+
predicate legalMergeCandidate(ClassObjectInternal cls) {
357+
this.legalMergeCandidate(cls, EmptyList())
358+
}
328359

360+
pragma[noinline]
329361
predicate illegalMergeCandidate(ClassObjectInternal cls) {
330-
exists(ClassList cl, int j |
331-
this.legalMergeCandidateNonEmpty(cls, _, cl, j + 1) and
332-
j >= 1 and
333-
cls = cl.getItem(j)
334-
)
362+
this.legalMergeCandidateNonEmpty(cls, _, Cons(cls, _))
335363
}
336364

337365
ClassObjectInternal bestMergeCandidate(int n) {
@@ -342,6 +370,7 @@ private class ClassListList extends TClassListList {
342370
)
343371
}
344372

373+
pragma[noinline]
345374
ClassObjectInternal bestMergeCandidate() { result = this.bestMergeCandidate(0) }
346375

347376
/**

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

Lines changed: 115 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,20 +1429,51 @@ module Expressions {
14291429
}
14301430

14311431
pragma[noinline]
1432-
predicate subscriptPointsTo(
1432+
private predicate indexPointsToInt(ControlFlowNode index, PointsToContext context, int n) {
1433+
index = any(SubscriptNode subscr).getIndex() and
1434+
PointsToInternal::pointsTo(index, context, TInt(n), _)
1435+
}
1436+
1437+
pragma[noinline]
1438+
private predicate getItemSequenceObjectInternal(
1439+
ObjectInternal value, SequenceObjectInternal objvalue, int n
1440+
) {
1441+
value = objvalue.getItem(n)
1442+
}
1443+
1444+
pragma[noinline]
1445+
private predicate subscriptObjectAndIndexPointsToInt(
1446+
SubscriptNode subscr, PointsToContext context, ControlFlowNode obj, ObjectInternal objvalue,
1447+
int n
1448+
) {
1449+
exists(ControlFlowNode index |
1450+
subscriptObjectAndIndex(subscr, context, obj, objvalue, index) and
1451+
indexPointsToInt(index, context, n)
1452+
)
1453+
}
1454+
1455+
deprecated predicate subscriptPointsTo(
14331456
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
14341457
ControlFlowNode obj, ObjectInternal objvalue
1458+
) {
1459+
subscriptPointsTo(subscr, context, value, obj, objvalue) and
1460+
origin = subscr
1461+
}
1462+
1463+
pragma[noinline]
1464+
private predicate subscriptPointsTo(
1465+
SubscriptNode subscr, PointsToContext context, ObjectInternal value, ControlFlowNode obj,
1466+
ObjectInternal objvalue
14351467
) {
14361468
exists(ControlFlowNode index | subscriptObjectAndIndex(subscr, context, obj, objvalue, index) |
14371469
objvalue.subscriptUnknown() and
14381470
value = ObjectInternal::unknown()
1439-
or
1440-
exists(int n |
1441-
PointsToInternal::pointsTo(index, context, TInt(n), _) and
1442-
value = objvalue.(SequenceObjectInternal).getItem(n)
1443-
)
1444-
) and
1445-
origin = subscr
1471+
)
1472+
or
1473+
exists(int n |
1474+
subscriptObjectAndIndexPointsToInt(subscr, context, obj, objvalue, n) and
1475+
getItemSequenceObjectInternal(value, objvalue, n)
1476+
)
14461477
}
14471478

14481479
predicate subscriptPartsPointsTo(
@@ -1466,15 +1497,22 @@ module Expressions {
14661497
index = subscr.getIndex()
14671498
}
14681499

1500+
deprecated predicate binaryPointsTo(
1501+
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
1502+
ControlFlowNode operand, ObjectInternal opvalue
1503+
) {
1504+
binaryPointsTo(b, context, value, operand, opvalue) and
1505+
origin = b
1506+
}
1507+
14691508
/**
14701509
* Tracking too many binary expressions is likely to kill performance, so just say anything other than addition or bitwise or is 'unknown'.
14711510
*/
14721511
pragma[noinline]
1473-
predicate binaryPointsTo(
1474-
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
1475-
ControlFlowNode operand, ObjectInternal opvalue
1512+
private predicate binaryPointsTo(
1513+
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
1514+
ObjectInternal opvalue
14761515
) {
1477-
origin = b and
14781516
operand = genericBinaryOperand(b) and
14791517
PointsToInternal::pointsTo(operand, context, opvalue, _) and
14801518
value = ObjectInternal::unknown()
@@ -1491,12 +1529,19 @@ module Expressions {
14911529
)
14921530
}
14931531

1494-
pragma[noinline]
1495-
predicate addPointsTo(
1532+
deprecated predicate addPointsTo(
14961533
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
14971534
ControlFlowNode operand, ObjectInternal opvalue
14981535
) {
1499-
origin = b and
1536+
addPointsTo(b, context, value, operand, opvalue) and
1537+
origin = b
1538+
}
1539+
1540+
pragma[noinline]
1541+
private predicate addPointsTo(
1542+
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
1543+
ObjectInternal opvalue
1544+
) {
15001545
exists(Operator op |
15011546
b.operands(operand, op, _)
15021547
or
@@ -1508,12 +1553,19 @@ module Expressions {
15081553
)
15091554
}
15101555

1511-
pragma[noinline]
1512-
predicate bitOrPointsTo(
1556+
deprecated predicate bitOrPointsTo(
15131557
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
15141558
ControlFlowNode operand, ObjectInternal opvalue
15151559
) {
1516-
origin = b and
1560+
bitOrPointsTo(b, context, value, operand, opvalue) and
1561+
origin = b
1562+
}
1563+
1564+
pragma[noinline]
1565+
private predicate bitOrPointsTo(
1566+
BinaryExprNode b, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
1567+
ObjectInternal opvalue
1568+
) {
15171569
exists(Operator op, ControlFlowNode other |
15181570
b.operands(operand, op, other)
15191571
or
@@ -1533,10 +1585,18 @@ module Expressions {
15331585
value = obj.intValue()
15341586
}
15351587

1536-
pragma[noinline]
1537-
predicate unaryPointsTo(
1588+
deprecated predicate unaryPointsTo(
15381589
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
15391590
ControlFlowNode operand, ObjectInternal opvalue
1591+
) {
1592+
unaryPointsTo(u, context, value, operand, opvalue) and
1593+
origin = u
1594+
}
1595+
1596+
pragma[noinline]
1597+
private predicate unaryPointsTo(
1598+
UnaryExprNode u, PointsToContext context, ObjectInternal value, ControlFlowNode operand,
1599+
ObjectInternal opvalue
15401600
) {
15411601
exists(Unaryop op |
15421602
op = u.getNode().getOp() and
@@ -1548,14 +1608,21 @@ module Expressions {
15481608
op instanceof USub and value = ObjectInternal::fromInt(-opvalue.intValue())
15491609
or
15501610
not op instanceof Not and opvalue = ObjectInternal::unknown() and value = opvalue
1551-
) and
1552-
origin = u
1611+
)
15531612
}
15541613

1555-
pragma[noinline]
1556-
predicate builtinCallPointsTo(
1614+
deprecated predicate builtinCallPointsTo(
15571615
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
15581616
ControlFlowNode arg, ObjectInternal argvalue
1617+
) {
1618+
builtinCallPointsTo(call, context, value, arg, argvalue) and
1619+
origin = call
1620+
}
1621+
1622+
pragma[noinline]
1623+
private predicate builtinCallPointsTo(
1624+
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
1625+
ObjectInternal argvalue
15591626
) {
15601627
PointsToInternal::pointsTo(arg, context, argvalue, _) and
15611628
arg = call.getArg(0) and
@@ -1569,8 +1636,7 @@ module Expressions {
15691636
callable != ObjectInternal::builtin("hasattr") and
15701637
callable.isClass() = false and
15711638
value = ObjectInternal::unknown()
1572-
) and
1573-
origin = call
1639+
)
15741640
}
15751641

15761642
pragma[noinline]
@@ -1585,11 +1651,10 @@ module Expressions {
15851651

15861652
pragma[noinline]
15871653
private predicate lenCallPointsTo(
1588-
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode origin,
1589-
ControlFlowNode arg, ObjectInternal argvalue
1654+
CallNode call, PointsToContext context, ObjectInternal value, ControlFlowNode arg,
1655+
ObjectInternal argvalue
15901656
) {
15911657
len_call(call, arg, context, argvalue) and
1592-
origin = call and
15931658
exists(int len | len = argvalue.length() |
15941659
value = TInt(len) and len >= 0
15951660
or
@@ -1815,19 +1880,26 @@ module Expressions {
18151880
) {
18161881
attributePointsTo(expr, context, value, origin, subexpr, subvalue)
18171882
or
1818-
subscriptPointsTo(expr, context, value, origin, subexpr, subvalue)
1883+
subscriptPointsTo(expr, context, value, subexpr, subvalue) and
1884+
origin = expr
18191885
or
1820-
addPointsTo(expr, context, value, origin, subexpr, subvalue)
1886+
addPointsTo(expr, context, value, subexpr, subvalue) and
1887+
origin = expr
18211888
or
1822-
bitOrPointsTo(expr, context, value, origin, subexpr, subvalue)
1889+
bitOrPointsTo(expr, context, value, subexpr, subvalue) and
1890+
origin = expr
18231891
or
1824-
binaryPointsTo(expr, context, value, origin, subexpr, subvalue)
1892+
binaryPointsTo(expr, context, value, subexpr, subvalue) and
1893+
origin = expr
18251894
or
1826-
unaryPointsTo(expr, context, value, origin, subexpr, subvalue)
1895+
unaryPointsTo(expr, context, value, subexpr, subvalue) and
1896+
origin = expr
18271897
or
1828-
builtinCallPointsTo(expr, context, value, origin, subexpr, subvalue)
1898+
builtinCallPointsTo(expr, context, value, subexpr, subvalue) and
1899+
origin = expr
18291900
or
1830-
lenCallPointsTo(expr, context, value, origin, subexpr, subvalue)
1901+
lenCallPointsTo(expr, context, value, subexpr, subvalue) and
1902+
origin = expr
18311903
or
18321904
typeCallPointsTo(expr, context, value, origin, subexpr, subvalue)
18331905
or
@@ -2068,6 +2140,12 @@ module Conditionals {
20682140
}
20692141
}
20702142

2143+
/** INTERNAL: Do not use. */
2144+
predicate declaredAttributeVar(PythonClassObjectInternal cls, string name, EssaVariable var) {
2145+
name = var.getName() and
2146+
var.getAUse() = cls.getScope().getANormalExit()
2147+
}
2148+
20712149
cached
20722150
module Types {
20732151
cached
@@ -2163,8 +2241,7 @@ module Types {
21632241
or
21642242
value != ObjectInternal::undefined() and
21652243
exists(EssaVariable var |
2166-
name = var.getName() and
2167-
var.getAUse() = cls.(PythonClassObjectInternal).getScope().getANormalExit() and
2244+
declaredAttributeVar(cls, name, var) and
21682245
PointsToInternal::variablePointsTo(var, _, value, origin)
21692246
)
21702247
}

0 commit comments

Comments
 (0)