Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ddc4ada

Browse files
committed
Python points-to: Handle subclassing of ABCs.
1 parent 2d4f64f commit ddc4ada

6 files changed

Lines changed: 68 additions & 27 deletions

File tree

python/ql/src/semmle/python/objects/Classes.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,19 @@ abstract class ClassObjectInternal extends ObjectInternal {
6262

6363
override int length() { none() }
6464

65+
boolean isIterableSubclass() {
66+
this = ObjectInternal::builtin("list") and result = true
67+
or
68+
this = ObjectInternal::builtin("set") and result = true
69+
or
70+
this = ObjectInternal::builtin("dict") and result = true
71+
or
72+
this != ObjectInternal::builtin("list") and
73+
this != ObjectInternal::builtin("set") and
74+
this != ObjectInternal::builtin("dict") and
75+
result = false
76+
}
77+
6578
}
6679

6780
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {

python/ql/src/semmle/python/objects/Instances.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ class SpecificInstanceInternal extends TSpecificInstance, ObjectInternal {
3131

3232
override boolean isClass() { result = false }
3333

34-
override boolean isComparable() { result = false }
34+
override boolean isComparable() { result = true }
3535

3636
override ObjectInternal getClass() {
3737
this = TSpecificInstance(_, result, _)

python/ql/src/semmle/python/objects/TObject.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,8 @@ predicate literal_instantiation(ControlFlowNode n, ClassObjectInternal cls, Poin
159159
or
160160
n instanceof DictNode and cls = ObjectInternal::builtin("dict")
161161
or
162+
n instanceof SetNode and cls = ObjectInternal::builtin("set")
163+
or
162164
n.getNode() instanceof ImaginaryLiteral and cls = ObjectInternal::builtin("complex")
163165
)
164166
}

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

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1746,10 +1746,23 @@ cached module Types {
17461746
or
17471747
mro.getItem(n) = sup and result = true
17481748
or
1749-
mro.getItem(n) != sup and result = mroContains(mro, sup, n+1)
1749+
mro.getItem(n) = abc_to_concrete(sup) and result = true
1750+
or
1751+
mro.getItem(n) != sup and sup != AbstractBaseClass::named("Iterable") and
1752+
mro.getItem(n) != abc_to_concrete(sup) and result = mroContains(mro, sup, n+1)
1753+
or
1754+
sup = AbstractBaseClass::named("Iterable") and result = mro.getItem(n).isIterableSubclass()
17501755
)
17511756
}
17521757

1758+
private ClassObjectInternal abc_to_concrete(ClassObjectInternal c) {
1759+
c = AbstractBaseClass::named("Sequence") and result = ObjectInternal::builtin("list")
1760+
or
1761+
c = AbstractBaseClass::named("Set") and result = ObjectInternal::builtin("set")
1762+
or
1763+
c = AbstractBaseClass::named("Mapping") and result = ObjectInternal::builtin("dict")
1764+
}
1765+
17531766
cached boolean hasAttr(ObjectInternal cls, string name) {
17541767
result = mroHasAttr(Types::getMro(cls), name, 0)
17551768
}
@@ -1776,6 +1789,19 @@ cached module Types {
17761789
}
17771790

17781791

1792+
module AbstractBaseClass {
1793+
1794+
ClassObjectInternal named(string name) {
1795+
exists(ModuleObjectInternal m |
1796+
m.getName() = "_abcoll"
1797+
or
1798+
m.getName() = "_collections_abc"
1799+
|
1800+
m.attribute(name, result, _)
1801+
)
1802+
}
1803+
}
1804+
17791805
module AttributePointsTo {
17801806

17811807
predicate pointsTo(AttrNode f, Context context, ObjectInternal value, ControlFlowNode origin) {
Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,30 @@
11
| import | test.py:17:1:17:3 | ControlFlowNode for bar | Function bar | test.py:2:1:2:19 | ControlFlowNode for FunctionExpr |
2-
| import | test.py:18:1:18:7 | ControlFlowNode for bar() | 21 | test.py:18:5:18:6 | ControlFlowNode for IntegerLiteral |
3-
| import | test.py:19:1:19:13 | ControlFlowNode for bar() | 22 | test.py:19:5:19:6 | ControlFlowNode for IntegerLiteral |
4-
| import | test.py:20:1:20:13 | ControlFlowNode for bar() | True | test.py:20:9:20:12 | ControlFlowNode for True |
5-
| import | test.py:21:1:21:11 | ControlFlowNode for bar() | 24 | test.py:21:5:21:6 | ControlFlowNode for IntegerLiteral |
6-
| import | test.py:22:1:22:13 | ControlFlowNode for bar() | 7 | test.py:22:7:22:7 | ControlFlowNode for IntegerLiteral |
2+
| import | test.py:18:1:18:7 | ControlFlowNode for bar() | int 21 | test.py:18:5:18:6 | ControlFlowNode for IntegerLiteral |
3+
| import | test.py:19:1:19:13 | ControlFlowNode for bar() | int 22 | test.py:19:5:19:6 | ControlFlowNode for IntegerLiteral |
4+
| import | test.py:20:1:20:13 | ControlFlowNode for bar() | bool True | test.py:20:9:20:12 | ControlFlowNode for True |
5+
| import | test.py:21:1:21:11 | ControlFlowNode for bar() | int 24 | test.py:21:5:21:6 | ControlFlowNode for IntegerLiteral |
6+
| import | test.py:22:1:22:13 | ControlFlowNode for bar() | int 7 | test.py:22:7:22:7 | ControlFlowNode for IntegerLiteral |
77
| runtime | test.py:4:5:4:5 | ControlFlowNode for b | None | test.py:2:14:2:17 | ControlFlowNode for None |
88
| runtime | test.py:11:5:11:7 | ControlFlowNode for bar | Function bar | test.py:2:1:2:19 | ControlFlowNode for FunctionExpr |
9-
| runtime | test.py:12:5:12:11 | ControlFlowNode for bar() | 11 | test.py:12:9:12:10 | ControlFlowNode for IntegerLiteral |
10-
| runtime | test.py:13:5:13:17 | ControlFlowNode for bar() | 12 | test.py:13:9:13:10 | ControlFlowNode for IntegerLiteral |
11-
| runtime | test.py:14:5:14:17 | ControlFlowNode for bar() | True | test.py:14:13:14:16 | ControlFlowNode for True |
12-
| runtime | test.py:15:5:15:15 | ControlFlowNode for bar() | 14 | test.py:15:9:15:10 | ControlFlowNode for IntegerLiteral |
13-
| test.py:12 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | 11 | test.py:12:9:12:10 | ControlFlowNode for IntegerLiteral |
9+
| runtime | test.py:12:5:12:11 | ControlFlowNode for bar() | int 11 | test.py:12:9:12:10 | ControlFlowNode for IntegerLiteral |
10+
| runtime | test.py:13:5:13:17 | ControlFlowNode for bar() | int 12 | test.py:13:9:13:10 | ControlFlowNode for IntegerLiteral |
11+
| runtime | test.py:14:5:14:17 | ControlFlowNode for bar() | bool True | test.py:14:13:14:16 | ControlFlowNode for True |
12+
| runtime | test.py:15:5:15:15 | ControlFlowNode for bar() | int 14 | test.py:15:9:15:10 | ControlFlowNode for IntegerLiteral |
13+
| test.py:12 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | int 11 | test.py:12:9:12:10 | ControlFlowNode for IntegerLiteral |
1414
| test.py:12 from runtime | test.py:4:5:4:5 | ControlFlowNode for b | None | test.py:2:14:2:17 | ControlFlowNode for None |
15-
| test.py:13 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | 12 | test.py:13:9:13:10 | ControlFlowNode for IntegerLiteral |
15+
| test.py:13 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | int 12 | test.py:13:9:13:10 | ControlFlowNode for IntegerLiteral |
1616
| test.py:13 from runtime | test.py:4:5:4:5 | ControlFlowNode for b | None | test.py:13:13:13:16 | ControlFlowNode for None |
17-
| test.py:14 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | 13 | test.py:14:9:14:10 | ControlFlowNode for IntegerLiteral |
18-
| test.py:14 from runtime | test.py:4:5:4:5 | ControlFlowNode for b | True | test.py:14:13:14:16 | ControlFlowNode for True |
19-
| test.py:15 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | 14 | test.py:15:9:15:10 | ControlFlowNode for IntegerLiteral |
17+
| test.py:14 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | int 13 | test.py:14:9:14:10 | ControlFlowNode for IntegerLiteral |
18+
| test.py:14 from runtime | test.py:4:5:4:5 | ControlFlowNode for b | bool True | test.py:14:13:14:16 | ControlFlowNode for True |
19+
| test.py:15 from runtime | test.py:3:5:3:5 | ControlFlowNode for a | int 14 | test.py:15:9:15:10 | ControlFlowNode for IntegerLiteral |
2020
| test.py:15 from runtime | test.py:4:5:4:5 | ControlFlowNode for b | '' | test.py:15:13:15:14 | ControlFlowNode for Str |
21-
| test.py:18 from import | test.py:3:5:3:5 | ControlFlowNode for a | 21 | test.py:18:5:18:6 | ControlFlowNode for IntegerLiteral |
21+
| test.py:18 from import | test.py:3:5:3:5 | ControlFlowNode for a | int 21 | test.py:18:5:18:6 | ControlFlowNode for IntegerLiteral |
2222
| test.py:18 from import | test.py:4:5:4:5 | ControlFlowNode for b | None | test.py:2:14:2:17 | ControlFlowNode for None |
23-
| test.py:19 from import | test.py:3:5:3:5 | ControlFlowNode for a | 22 | test.py:19:5:19:6 | ControlFlowNode for IntegerLiteral |
23+
| test.py:19 from import | test.py:3:5:3:5 | ControlFlowNode for a | int 22 | test.py:19:5:19:6 | ControlFlowNode for IntegerLiteral |
2424
| test.py:19 from import | test.py:4:5:4:5 | ControlFlowNode for b | None | test.py:19:9:19:12 | ControlFlowNode for None |
25-
| test.py:20 from import | test.py:3:5:3:5 | ControlFlowNode for a | 23 | test.py:20:5:20:6 | ControlFlowNode for IntegerLiteral |
26-
| test.py:20 from import | test.py:4:5:4:5 | ControlFlowNode for b | True | test.py:20:9:20:12 | ControlFlowNode for True |
27-
| test.py:21 from import | test.py:3:5:3:5 | ControlFlowNode for a | 24 | test.py:21:5:21:6 | ControlFlowNode for IntegerLiteral |
25+
| test.py:20 from import | test.py:3:5:3:5 | ControlFlowNode for a | int 23 | test.py:20:5:20:6 | ControlFlowNode for IntegerLiteral |
26+
| test.py:20 from import | test.py:4:5:4:5 | ControlFlowNode for b | bool True | test.py:20:9:20:12 | ControlFlowNode for True |
27+
| test.py:21 from import | test.py:3:5:3:5 | ControlFlowNode for a | int 24 | test.py:21:5:21:6 | ControlFlowNode for IntegerLiteral |
2828
| test.py:21 from import | test.py:4:5:4:5 | ControlFlowNode for b | '' | test.py:21:9:21:10 | ControlFlowNode for Str |
29-
| test.py:22 from import | test.py:3:5:3:5 | ControlFlowNode for a | 3 | test.py:22:12:22:12 | ControlFlowNode for IntegerLiteral |
30-
| test.py:22 from import | test.py:4:5:4:5 | ControlFlowNode for b | 7 | test.py:22:7:22:7 | ControlFlowNode for IntegerLiteral |
29+
| test.py:22 from import | test.py:3:5:3:5 | ControlFlowNode for a | int 3 | test.py:22:12:22:12 | ControlFlowNode for IntegerLiteral |
30+
| test.py:22 from import | test.py:4:5:4:5 | ControlFlowNode for b | int 7 | test.py:22:7:22:7 | ControlFlowNode for IntegerLiteral |

python/ql/test/library-tests/PointsTo/global/Global.ql

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import python
33

44

55
import python
6-
import semmle.python.pointsto.PointsTo2
7-
import semmle.python.pointsto.PointsToContext2
6+
import semmle.python.pointsto.PointsTo
7+
import semmle.python.pointsto.PointsToContext
88
import semmle.python.objects.ObjectInternal
99

10-
from ControlFlowNode f, PointsToContext2 ctx, ObjectInternal obj, ControlFlowNode orig
10+
from ControlFlowNode f, PointsToContext ctx, Value obj, ControlFlowNode orig
1111
where exists(ExprStmt s | s.getValue().getAFlowNode() = f) and
12-
PointsTo2::points_to(f, ctx, obj, orig)
12+
PointsTo::pointsTo(f, ctx, obj, orig)
1313

1414
select ctx, f, obj.toString(), orig

0 commit comments

Comments
 (0)