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

Skip to content

Commit 2f940d0

Browse files
committed
Python points-to: Fully document object classes.
1 parent d6d72dc commit 2f940d0

11 files changed

Lines changed: 306 additions & 115 deletions

File tree

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

Lines changed: 31 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,54 +11,49 @@ private import semmle.python.types.Builtins
1111

1212
abstract class CallableObjectInternal extends ObjectInternal {
1313

14-
override int intValue() {
15-
none()
16-
}
17-
18-
override string strValue() {
19-
none()
20-
}
14+
/** Gets the name of this callable */
15+
abstract string getName();
2116

22-
override boolean isClass() { result = false }
17+
/** Gets the scope of this callable if it has one */
18+
abstract Function getScope();
2319

24-
/** The boolean value of this object, if it has one */
25-
override boolean booleanValue() {
26-
result = true
27-
}
20+
/** Gets a call to this callable from the given context */
21+
abstract CallNode getACall(PointsToContext ctx);
2822

29-
override ClassDecl getClassDeclaration() {
30-
none()
31-
}
23+
/** Gets a call to this callable */
24+
CallNode getACall() { result = this.getACall(_) }
3225

33-
abstract string getName();
26+
override boolean isClass() { result = false }
3427

35-
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
36-
none()
37-
}
28+
override boolean booleanValue() { result = true }
3829

39-
pragma [noinline] override predicate attributesUnknown() { none() }
40-
41-
abstract Function getScope();
30+
override ClassDecl getClassDeclaration() { none() }
4231

4332
pragma [noinline] override predicate binds(ObjectInternal instance, string name, ObjectInternal descriptor) { none() }
4433

45-
abstract CallNode getACall(PointsToContext ctx);
46-
47-
CallNode getACall() { result = this.getACall(_) }
48-
4934
abstract NameNode getParameter(int n);
5035

5136
abstract NameNode getParameterByName(string name);
5237

38+
abstract predicate neverReturns();
39+
5340
override int length() { none() }
5441

55-
abstract predicate neverReturns();
42+
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
43+
none()
44+
}
45+
46+
pragma [noinline] override predicate attributesUnknown() { none() }
5647

5748
override predicate subscriptUnknown() { none() }
5849

59-
}
50+
override int intValue() { none() }
51+
52+
override string strValue() { none() }
6053

54+
}
6155

56+
/** Class representing Python functions */
6257
class PythonFunctionObjectInternal extends CallableObjectInternal, TPythonFunctionObject {
6358

6459
override Function getScope() {
@@ -176,6 +171,7 @@ private BasicBlock blockReturningNone(Function func) {
176171
}
177172

178173

174+
/** Class representing built-in functions such as `len` or `print`. */
179175
class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunctionObject {
180176

181177
override Builtin getBuiltin() {
@@ -283,7 +279,8 @@ class BuiltinFunctionObjectInternal extends CallableObjectInternal, TBuiltinFunc
283279

284280
}
285281

286-
282+
/** Class representing methods of built-in classes (otherwise known as method-descriptors) such as `list.append`.
283+
*/
287284
class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethodObject {
288285

289286
override Builtin getBuiltin() {
@@ -372,6 +369,11 @@ class BuiltinMethodObjectInternal extends CallableObjectInternal, TBuiltinMethod
372369

373370
}
374371

372+
/** Class representing bound-methods.
373+
* Note that built-in methods, such as `[].append` are also represented as bound-methods.
374+
* Although built-in methods and bound-methods are distinct classes in CPython, their behaviour
375+
* is the same and we treat them identically.
376+
*/
375377
class BoundMethodObjectInternal extends CallableObjectInternal, TBoundMethod {
376378

377379
override Builtin getBuiltin() {

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

Lines changed: 44 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,9 @@ private import semmle.python.pointsto.PointsToContext
88
private import semmle.python.pointsto.MRO
99
private import semmle.python.types.Builtins
1010

11-
11+
/** Class representing classes */
1212
abstract class ClassObjectInternal extends ObjectInternal {
1313

14-
override boolean booleanValue() {
15-
result = true
16-
}
17-
18-
override boolean isClass() { result = true }
19-
20-
override int intValue() {
21-
none()
22-
}
23-
24-
override string strValue() {
25-
none()
26-
}
27-
2814
string getName() {
2915
result = this.getClassDeclaration().getName()
3016
}
@@ -33,6 +19,33 @@ abstract class ClassObjectInternal extends ObjectInternal {
3319
result = Types::getMro(this).isSpecial()
3420
}
3521

22+
/** Looks up the attribute `name` on this class.
23+
* Note that this may be different from `this.attr(name)`.
24+
* For example given the class:
25+
* ```class C:
26+
* @classmethod
27+
* def f(cls): pass
28+
* ```
29+
* `this.lookup("f")` is equivent to `C.__dict__['f']`, which is the class-method
30+
* whereas
31+
* `this.attr("f") is equivalent to `C.f`, which is a bound-method.
32+
*/
33+
abstract predicate lookup(string name, ObjectInternal value, CfgOrigin origin);
34+
35+
/** Holds if this is a subclass of the `Iterable` abstract base class. */
36+
boolean isIterableSubclass() {
37+
this = ObjectInternal::builtin("list") and result = true
38+
or
39+
this = ObjectInternal::builtin("set") and result = true
40+
or
41+
this = ObjectInternal::builtin("dict") and result = true
42+
or
43+
this != ObjectInternal::builtin("list") and
44+
this != ObjectInternal::builtin("set") and
45+
this != ObjectInternal::builtin("dict") and
46+
result = false
47+
}
48+
3649
override boolean isDescriptor() { result = false }
3750

3851
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
@@ -46,8 +59,6 @@ abstract class ClassObjectInternal extends ObjectInternal {
4659
descriptor.isDescriptor() = true
4760
}
4861

49-
abstract predicate lookup(string name, ObjectInternal value, CfgOrigin origin);
50-
5162
/** Approximation to descriptor protocol, skipping meta-descriptor protocol */
5263
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
5364
exists(ObjectInternal descriptor, CfgOrigin desc_origin |
@@ -62,24 +73,25 @@ abstract class ClassObjectInternal extends ObjectInternal {
6273

6374
override int length() { none() }
6475

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+
override boolean booleanValue() { result = true }
77+
78+
override boolean isClass() { result = true }
79+
80+
override int intValue() {
81+
none()
82+
}
83+
84+
override string strValue() {
85+
none()
7686
}
7787

7888
override predicate subscriptUnknown() { none() }
7989
}
8090

91+
/** Class representing Python source classes */
8192
class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject {
8293

94+
/** Gets the scope for this Python class */
8395
Class getScope() {
8496
exists(ClassExpr expr |
8597
this = TPythonClassObject(expr.getAFlowNode()) and
@@ -141,6 +153,7 @@ class PythonClassObjectInternal extends ClassObjectInternal, TPythonClassObject
141153

142154
}
143155

156+
/** Class representing built-in classes, except `type` */
144157
class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObject {
145158

146159
override Builtin getBuiltin() {
@@ -194,7 +207,7 @@ class BuiltinClassObjectInternal extends ClassObjectInternal, TBuiltinClassObjec
194207

195208
}
196209

197-
210+
/** A class representing an unknown class */
198211
class UnknownClassInternal extends ClassObjectInternal, TUnknownClass {
199212

200213
override string toString() {
@@ -243,6 +256,7 @@ class UnknownClassInternal extends ClassObjectInternal, TUnknownClass {
243256

244257
}
245258

259+
/** A class representing the built-in class `type`. */
246260
class TypeInternal extends ClassObjectInternal, TType {
247261

248262
override string toString() {
@@ -292,6 +306,7 @@ class TypeInternal extends ClassObjectInternal, TType {
292306

293307
}
294308

309+
/** A class representing a dynamically created class `type(name, *args, **kwargs)`. */
295310
class DynamicallyCreatedClass extends ClassObjectInternal, TDynamicClass {
296311

297312
override string toString() {

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

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ private import semmle.python.pointsto.PointsToContext
88
private import semmle.python.types.Builtins
99

1010

11-
11+
/** Class representing constants.
12+
* Includes `None`, `True` and `False` as
13+
* well as strings and integers.
14+
*/
1215
abstract class ConstantObjectInternal extends ObjectInternal {
1316

1417
override ClassDecl getClassDeclaration() {
@@ -66,7 +69,7 @@ abstract class ConstantObjectInternal extends ObjectInternal {
6669

6770
}
6871

69-
abstract class BooleanObjectInternal extends ConstantObjectInternal {
72+
private abstract class BooleanObjectInternal extends ConstantObjectInternal {
7073

7174
BooleanObjectInternal() {
7275
this = TTrue() or this = TFalse()
@@ -79,9 +82,13 @@ abstract class BooleanObjectInternal extends ConstantObjectInternal {
7982

8083
override int length() { none() }
8184

85+
override string strValue() {
86+
none()
87+
}
88+
8289
}
8390

84-
class TrueObjectInternal extends BooleanObjectInternal, TTrue {
91+
private class TrueObjectInternal extends BooleanObjectInternal, TTrue {
8592

8693
override string toString() {
8794
result = "bool True"
@@ -99,17 +106,13 @@ class TrueObjectInternal extends BooleanObjectInternal, TTrue {
99106
result = 1
100107
}
101108

102-
override string strValue() {
103-
none()
104-
}
105-
106109
override Builtin getBuiltin() {
107110
result = Builtin::special("True")
108111
}
109112

110113
}
111114

112-
class FalseObjectInternal extends BooleanObjectInternal, TFalse {
115+
private class FalseObjectInternal extends BooleanObjectInternal, TFalse {
113116

114117
override string toString() {
115118
result = "bool False"
@@ -127,17 +130,13 @@ class FalseObjectInternal extends BooleanObjectInternal, TFalse {
127130
result = 0
128131
}
129132

130-
override string strValue() {
131-
none()
132-
}
133-
134133
override Builtin getBuiltin() {
135134
result = Builtin::special("False")
136135
}
137136

138137
}
139138

140-
class NoneObjectInternal extends ConstantObjectInternal, TNone {
139+
private class NoneObjectInternal extends ConstantObjectInternal, TNone {
141140

142141
override string toString() {
143142
result = "None"
@@ -172,7 +171,7 @@ class NoneObjectInternal extends ConstantObjectInternal, TNone {
172171
}
173172

174173

175-
class IntObjectInternal extends ConstantObjectInternal, TInt {
174+
private class IntObjectInternal extends ConstantObjectInternal, TInt {
176175

177176
override string toString() {
178177
result = "int " + this.intValue().toString()
@@ -209,7 +208,7 @@ class IntObjectInternal extends ConstantObjectInternal, TInt {
209208

210209
}
211210

212-
class FloatObjectInternal extends ConstantObjectInternal, TFloat {
211+
private class FloatObjectInternal extends ConstantObjectInternal, TFloat {
213212

214213
override string toString() {
215214
if this.floatValue() = this.floatValue().floor() then (
@@ -255,7 +254,7 @@ class FloatObjectInternal extends ConstantObjectInternal, TFloat {
255254
}
256255

257256

258-
class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
257+
private class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
259258

260259
override string toString() {
261260
result = "'" + this.strValue() + "'"
@@ -296,7 +295,7 @@ class UnicodeObjectInternal extends ConstantObjectInternal, TUnicode {
296295

297296
}
298297

299-
class BytesObjectInternal extends ConstantObjectInternal, TBytes {
298+
private class BytesObjectInternal extends ConstantObjectInternal, TBytes {
300299

301300
override string toString() {
302301
result = "'" + this.strValue() + "'"

0 commit comments

Comments
 (0)