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

Skip to content

Commit 3986159

Browse files
committed
Python points-to: Fix up handiling of metaclasses, new-style and type-heirarchy failure analysis.
1 parent 93f0b8f commit 3986159

10 files changed

Lines changed: 89 additions & 11 deletions

File tree

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ module ObjectInternal {
411411
}
412412

413413
ObjectInternal type() {
414-
result = TBuiltinClassObject(Builtin::special("type"))
414+
result = TType()
415415
}
416416

417417
ObjectInternal property() {

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

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -823,9 +823,15 @@ module InterProceduralPointsTo {
823823
/* A decorator and we don't understand it. Use the original, undecorated value */
824824
f.isDecoratorCall() and returnValue = ObjectInternal::unknown() and
825825
PointsToInternal::pointsTo(f.getArg(0), context, value, origin)
826+
or
827+
Types::six_add_metaclass(f, value, _) and
828+
PointsToInternal::pointsTo(f.getArg(0), context, value, origin)
826829
)
827830
or
828831
Expressions::typeCallPointsTo(f, context, value, origin, _, _)
832+
or
833+
Types::six_add_metaclass(f, value, _) and
834+
PointsToInternal::pointsTo(f.getArg(0), context, value, origin)
829835
}
830836

831837
/** Points-to for parameter. `def foo(param): ...`. */
@@ -1390,8 +1396,7 @@ module Expressions {
13901396
}
13911397

13921398
pragma [nomagic]
1393-
//private
1394-
boolean isinstanceEvaluatesTo(CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val) {
1399+
private boolean isinstanceEvaluatesTo(CallNode call, PointsToContext context, ControlFlowNode use, ObjectInternal val) {
13951400
exists(ObjectInternal cls |
13961401
isinstance_call(call, use, context, val, cls) |
13971402
result = Types::improperSubclass(val.getClass(), cls)
@@ -1637,9 +1642,9 @@ cached module Types {
16371642
n = count(pycls.getABase()) and result = false
16381643
)
16391644
or
1640-
hasDeclaredMetaclass(cls) = false and
16411645
exists(ClassObjectInternal base |
16421646
base = getBase(cls, n) |
1647+
hasDeclaredMetaclass(cls) = false and
16431648
isOldStyle(base) and result = newStylePython2(cls, n+1)
16441649
or
16451650
isNewStyle(base) and result = true
@@ -1738,7 +1743,6 @@ cached module Types {
17381743
cls.(ImportTimeScope).entryEdge(result.getAUse(), _)
17391744
}
17401745

1741-
/** INTERNAL -- Do not use */
17421746
cached predicate six_add_metaclass(CallNode decorator_call, ClassObjectInternal decorated, ControlFlowNode metaclass) {
17431747
exists(CallNode decorator |
17441748
PointsToInternal::pointsTo(decorator_call.getArg(0), _, decorated, _) and
@@ -1754,10 +1758,9 @@ cached module Types {
17541758
}
17551759

17561760
private ObjectInternal six_add_metaclass_function() {
1757-
exists(Module six, FunctionExpr add_metaclass |
1758-
add_metaclass.getInnerScope().getName() = "add_metaclass" and
1759-
add_metaclass.getScope() = six and
1760-
result.getOrigin() = add_metaclass.getAFlowNode()
1761+
exists(ModuleObjectInternal six |
1762+
six.getName() = "six" and
1763+
six.attribute("add_metaclass", result, _)
17611764
)
17621765
}
17631766

@@ -1812,7 +1815,7 @@ cached module Types {
18121815
or
18131816
reason = "Missing base " + missingBase(cls)
18141817
or
1815-
exists(cls.(PythonClassObjectInternal).getScope().getMetaClass()) and not exists(cls.getClass()) and reason = "Failed to infer metaclass"
1818+
not exists(ObjectInternal meta | meta = cls.getClass() and not meta = ObjectInternal::unknownClass()) and reason = "Failed to infer metaclass"
18161819
or
18171820
exists(int i, ObjectInternal base1, ObjectInternal base2 |
18181821
base1 = getBase(cls, i) and
@@ -1831,7 +1834,7 @@ cached module Types {
18311834
private int missingBase(ClassObjectInternal cls) {
18321835
exists(cls.(PythonClassObjectInternal).getScope().getBase(result))
18331836
and
1834-
not exists(getBase(cls, result)) or getBase(cls, result) = ObjectInternal::unknownClass()
1837+
not exists(ObjectInternal base | base = getBase(cls, result) and not base = ObjectInternal::unknownClass())
18351838
}
18361839

18371840
private predicate duplicateBase(ClassObjectInternal cls) {

python/ql/src/semmle/python/types/ClassObject.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ class ClassObject extends Object {
7777
Types::isNewStyle(theClass())
7878
}
7979

80+
/** Whether this class is an old style class.
81+
An old style class is one does not inherit from `object`. */
82+
predicate isOldStyle() {
83+
Types::isOldStyle(theClass())
84+
}
85+
8086
/** Whether this class is a legal exception class.
8187
* What constitutes a legal exception class differs between major versions */
8288
predicate isLegalExceptionType() {
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| test.py:26:1:26:17 | class C5 | Failed to infer metaclass |
2+
| test.py:30:1:30:17 | class C6 | Decorator not understood |
3+
| test.py:30:1:30:17 | class C6 | Failed to infer metaclass |
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
2+
import python
3+
4+
from ClassObject cls, string reason
5+
6+
where cls.getPyClass().getEnclosingModule().getName() = "test"
7+
and cls.failedInference(reason)
8+
9+
select cls, reason
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
| class C1 | [C1, object] |
2+
| class C2 | [C2, object] |
3+
| class C3 | [C3, object] |
4+
| class C4 | [C4, C2, object] |
5+
| class Meta1 | [Meta1, type, object] |
6+
| class Meta2 | [Meta2, type, object] |
7+
| class NewStyleEvenForPython2 | [NewStyleEvenForPython2, object] |
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
2+
import python
3+
4+
private import semmle.python.objects.ObjectInternal
5+
private import semmle.python.pointsto.PointsTo
6+
7+
/** Make unknown type visible */
8+
class UnknownType extends UnknownClassInternal {
9+
10+
override string toString() { result = "*UNKNOWN TYPE" }
11+
12+
override string getName() { result = "UNKNOWN" }
13+
14+
}
15+
16+
from PythonClassObjectInternal cls
17+
where cls.getScope().getEnclosingModule().getName() = "test" and not Types::failedInference(cls, _)
18+
select cls.toString(), Types::getMro(cls)
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
| test.py:3:1:3:18 | class Meta1 | new |
2+
| test.py:6:1:6:18 | class Meta2 | new |
3+
| test.py:10:1:10:17 | class C1 | new |
4+
| test.py:14:1:14:17 | class C2 | new |
5+
| test.py:18:1:18:17 | class C3 | new |
6+
| test.py:22:1:22:21 | class C4 | new |
7+
| test.py:26:1:26:17 | class C5 | new |
8+
| test.py:30:1:30:17 | class C6 | new |
9+
| test.py:35:1:35:29 | class NewStyleEvenForPython2 | new |
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
2+
3+
import python
4+
5+
6+
from ClassObject cls, string style
7+
where cls.getPyClass().getEnclosingModule().getName() = "test"
8+
and (
9+
cls.isNewStyle() and style = "new"
10+
or
11+
cls.isOldStyle() and style = "old"
12+
)
13+
select cls, style

python/ql/test/library-tests/PointsTo/metaclass/test.ql

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11

22
import python
3+
private import semmle.python.objects.ObjectInternal
4+
5+
/** Make unknown type visible */
6+
class UnknownType extends UnknownClassInternal {
7+
8+
override string toString() { result = "*UNKNOWN TYPE" }
9+
10+
override string getName() { result = "UNKNOWN" }
11+
12+
}
313

414
from ClassObject cls
515
where cls.getPyClass().getEnclosingModule().getName() = "test"

0 commit comments

Comments
 (0)