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

Skip to content

Commit 2e8c7a9

Browse files
committed
Python points-to: Support property setters and deleters.
1 parent 9b00177 commit 2e8c7a9

4 files changed

Lines changed: 126 additions & 30 deletions

File tree

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

Lines changed: 80 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class PropertyInternal extends ObjectInternal, TProperty {
3232
private Context getContext() { this = TProperty(_,result, _) }
3333

3434
override string toString() {
35-
result = "property" + this.getName()
35+
result = "property " + this.getName()
3636
}
3737

3838
override boolean booleanValue() { result = true }
@@ -63,7 +63,9 @@ class PropertyInternal extends ObjectInternal, TProperty {
6363

6464
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
6565

66-
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) { none() }
66+
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
67+
value = TPropertySetterOrDeleter(this, name) and origin = CfgOrigin::unknown()
68+
}
6769

6870
pragma [noinline] override predicate attributesUnknown() { none() }
6971

@@ -100,6 +102,82 @@ class PropertyInternal extends ObjectInternal, TProperty {
100102

101103
}
102104

105+
private class PropertySetterOrDeleter extends ObjectInternal, TPropertySetterOrDeleter {
106+
107+
override string toString() {
108+
result = this.getProperty().toString() + "." + this.getName()
109+
}
110+
111+
override string getName() {
112+
this = TPropertySetterOrDeleter(_, result)
113+
}
114+
115+
PropertyInternal getProperty() {
116+
this = TPropertySetterOrDeleter(result, _)
117+
}
118+
119+
override predicate callResult(ObjectInternal obj, CfgOrigin origin) {
120+
exists(ControlFlowNode call |
121+
obj = this.getProperty() and obj = TProperty(call, _, _) and
122+
origin = CfgOrigin::fromCfgNode(call)
123+
)
124+
}
125+
126+
override predicate introducedAt(ControlFlowNode node, PointsToContext context) {
127+
none()
128+
}
129+
130+
override ClassDecl getClassDeclaration() { none() }
131+
132+
override boolean isClass() { result = false }
133+
134+
override ObjectInternal getClass() {
135+
result = TBuiltinClassObject(Builtin::special("MethodType"))
136+
}
137+
138+
override predicate notTestableForEquality() { none() }
139+
140+
override Builtin getBuiltin() { none() }
141+
142+
override ControlFlowNode getOrigin() { none() }
143+
144+
override predicate callResult(PointsToContext callee, ObjectInternal obj, CfgOrigin origin) { none() }
145+
146+
override int intValue() { none() }
147+
148+
override string strValue() { none() }
149+
150+
override boolean booleanValue() { result = true }
151+
152+
override predicate calleeAndOffset(Function scope, int paramOffset) { none() }
153+
154+
pragma [noinline] override predicate attribute(string name, ObjectInternal value, CfgOrigin origin) {
155+
none()
156+
}
157+
158+
pragma [noinline] override predicate attributesUnknown() { none() }
159+
160+
override predicate subscriptUnknown() { none() }
161+
162+
override boolean isDescriptor() { result = true }
163+
164+
override int length() { none() }
165+
166+
pragma [noinline] override predicate binds(ObjectInternal cls, string name, ObjectInternal descriptor) { none() }
167+
168+
override predicate contextSensitiveCallee() { none() }
169+
170+
override ObjectInternal getIterNext() { none() }
171+
172+
pragma [noinline] override predicate descriptorGetClass(ObjectInternal cls, ObjectInternal value, CfgOrigin origin) { none() }
173+
174+
pragma [noinline] override predicate descriptorGetInstance(ObjectInternal instance, ObjectInternal value, CfgOrigin origin) { none() }
175+
176+
override predicate useOriginAsLegacyObject() { none() }
177+
178+
}
179+
180+
103181
/** A class representing classmethods in Python */
104182
class ClassMethodObjectInternal extends ObjectInternal, TClassMethod {
105183

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ cached newtype TObject =
194194
PointsToInternal::pointsTo(call.getArg(0), ctx, getter, _)
195195
}
196196
or
197+
TPropertySetterOrDeleter(PropertyInternal property, string method) {
198+
exists(AttrNode attr |
199+
PointsToInternal::pointsTo(attr.getObject(method), _, property, _)
200+
) and
201+
( method = "setter" or method = "deleter" )
202+
}
203+
or
197204
/* Represents a dynamically created class */
198205
TDynamicClass(CallNode instantiation, ClassObjectInternal metacls, PointsToContext context) {
199206
PointsToInternal::pointsTo(instantiation.getFunction(), context, metacls, _) and
Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,31 @@
1-
| test.py:3:1:3:16 | test.py:3 | ControlFlowNode for ClassExpr | import | test.py:3:1:3:16 | class C | file://:0:0:0:0 | builtin-class type |
2-
| test.py:3:9:3:14 | test.py:3 | ControlFlowNode for object | import | file://:0:0:0:0 | builtin-class object | file://:0:0:0:0 | builtin-class type |
3-
| test.py:5:6:5:13 | test.py:5 | ControlFlowNode for property | import | file://:0:0:0:0 | builtin-class property | file://:0:0:0:0 | builtin-class type |
4-
| test.py:5:6:5:13 | test.py:5 | ControlFlowNode for property() | import | test.py:5:6:5:13 | property p | file://:0:0:0:0 | builtin-class property |
5-
| test.py:6:5:6:16 | test.py:6 | ControlFlowNode for FunctionExpr | import | test.py:6:5:6:16 | Function C.p | file://:0:0:0:0 | builtin-class function |
6-
| test.py:7:16:7:16 | test.py:7 | ControlFlowNode for IntegerLiteral | runtime | file://:0:0:0:0 | int 0 | file://:0:0:0:0 | builtin-class int |
7-
| test.py:9:1:9:16 | test.py:9 | ControlFlowNode for ClassExpr | import | test.py:9:1:9:16 | class D | file://:0:0:0:0 | builtin-class type |
8-
| test.py:9:9:9:14 | test.py:9 | ControlFlowNode for object | import | file://:0:0:0:0 | builtin-class object | file://:0:0:0:0 | builtin-class type |
9-
| test.py:11:5:11:23 | test.py:11 | ControlFlowNode for FunctionExpr | import | test.py:11:5:11:23 | Function D.__init__ | file://:0:0:0:0 | builtin-class function |
10-
| test.py:12:9:12:12 | test.py:12 | ControlFlowNode for self | runtime | test.py:11:18:11:21 | self instance of D | test.py:9:1:9:16 | class D |
11-
| test.py:12:18:12:18 | test.py:12 | ControlFlowNode for IntegerLiteral | runtime | file://:0:0:0:0 | int 0 | file://:0:0:0:0 | builtin-class int |
12-
| test.py:14:6:14:13 | test.py:14 | ControlFlowNode for property | import | file://:0:0:0:0 | builtin-class property | file://:0:0:0:0 | builtin-class type |
13-
| test.py:14:6:14:13 | test.py:14 | ControlFlowNode for property() | import | test.py:14:6:14:13 | property q | file://:0:0:0:0 | builtin-class property |
14-
| test.py:15:5:15:16 | test.py:15 | ControlFlowNode for FunctionExpr | import | test.py:15:5:15:16 | Function D.q | file://:0:0:0:0 | builtin-class function |
15-
| test.py:16:16:16:19 | test.py:16 | ControlFlowNode for self | runtime | test.py:15:11:15:14 | self instance of D | test.py:9:1:9:16 | class D |
16-
| test.py:18:6:18:6 | test.py:18 | ControlFlowNode for q | import | test.py:14:6:14:13 | property q | file://:0:0:0:0 | builtin-class property |
17-
| test.py:19:5:19:23 | test.py:19 | ControlFlowNode for FunctionExpr | import | test.py:19:5:19:23 | Function D.q | file://:0:0:0:0 | builtin-class function |
18-
| test.py:20:9:20:12 | test.py:20 | ControlFlowNode for self | runtime | test.py:19:11:19:14 | self instance of D | test.py:9:1:9:16 | class D |
19-
| test.py:22:1:22:14 | test.py:22 | ControlFlowNode for ClassExpr | import | test.py:22:1:22:14 | class E | file://:0:0:0:0 | builtin-class type |
20-
| test.py:22:9:22:9 | test.py:22 | ControlFlowNode for C | import | test.py:3:1:3:16 | class C | file://:0:0:0:0 | builtin-class type |
21-
| test.py:22:12:22:12 | test.py:22 | ControlFlowNode for D | import | test.py:9:1:9:16 | class D | file://:0:0:0:0 | builtin-class type |
22-
| test.py:25:1:25:1 | test.py:25 | ControlFlowNode for C | import | test.py:3:1:3:16 | class C | file://:0:0:0:0 | builtin-class type |
23-
| test.py:25:1:25:3 | test.py:25 | ControlFlowNode for Attribute | import | test.py:5:6:5:13 | property p | file://:0:0:0:0 | builtin-class property |
24-
| test.py:26:1:26:1 | test.py:26 | ControlFlowNode for D | import | test.py:9:1:9:16 | class D | file://:0:0:0:0 | builtin-class type |
25-
| test.py:26:1:26:3 | test.py:26 | ControlFlowNode for Attribute | import | test.py:18:6:18:13 | property q | file://:0:0:0:0 | builtin-class property |
26-
| test.py:27:1:27:1 | test.py:27 | ControlFlowNode for E | import | test.py:22:1:22:14 | class E | file://:0:0:0:0 | builtin-class type |
27-
| test.py:28:1:28:1 | test.py:28 | ControlFlowNode for E | import | test.py:22:1:22:14 | class E | file://:0:0:0:0 | builtin-class type |
1+
| test.py:3:1:3:16 | test.py:3 | ControlFlowNode for ClassExpr | import | class C | builtin-class type |
2+
| test.py:3:9:3:14 | test.py:3 | ControlFlowNode for object | import | builtin-class object | builtin-class type |
3+
| test.py:5:6:5:13 | test.py:5 | ControlFlowNode for property | import | builtin-class property | builtin-class type |
4+
| test.py:5:6:5:13 | test.py:5 | ControlFlowNode for property() | import | property p | builtin-class property |
5+
| test.py:6:5:6:16 | test.py:6 | ControlFlowNode for FunctionExpr | import | Function C.p | builtin-class function |
6+
| test.py:7:16:7:16 | test.py:7 | ControlFlowNode for IntegerLiteral | runtime | int 0 | builtin-class int |
7+
| test.py:9:1:9:16 | test.py:9 | ControlFlowNode for ClassExpr | import | class D | builtin-class type |
8+
| test.py:9:9:9:14 | test.py:9 | ControlFlowNode for object | import | builtin-class object | builtin-class type |
9+
| test.py:11:5:11:23 | test.py:11 | ControlFlowNode for FunctionExpr | import | Function D.__init__ | builtin-class function |
10+
| test.py:12:9:12:12 | test.py:12 | ControlFlowNode for self | runtime | self instance of D | class D |
11+
| test.py:12:18:12:18 | test.py:12 | ControlFlowNode for IntegerLiteral | runtime | int 0 | builtin-class int |
12+
| test.py:14:6:14:13 | test.py:14 | ControlFlowNode for property | import | builtin-class property | builtin-class type |
13+
| test.py:14:6:14:13 | test.py:14 | ControlFlowNode for property() | import | property q | builtin-class property |
14+
| test.py:15:5:15:16 | test.py:15 | ControlFlowNode for FunctionExpr | import | Function D.q | builtin-class function |
15+
| test.py:16:16:16:19 | test.py:16 | ControlFlowNode for self | runtime | self instance of D | class D |
16+
| test.py:18:6:18:6 | test.py:18 | ControlFlowNode for q | import | property q | builtin-class property |
17+
| test.py:18:6:18:13 | test.py:18 | ControlFlowNode for Attribute | import | property q.setter | builtin-class method |
18+
| test.py:18:6:18:13 | test.py:18 | ControlFlowNode for Attribute() | import | property q | builtin-class property |
19+
| test.py:19:5:19:23 | test.py:19 | ControlFlowNode for FunctionExpr | import | Function D.q | builtin-class function |
20+
| test.py:20:9:20:12 | test.py:20 | ControlFlowNode for self | runtime | self instance of D | class D |
21+
| test.py:22:1:22:14 | test.py:22 | ControlFlowNode for ClassExpr | import | class E | builtin-class type |
22+
| test.py:22:9:22:9 | test.py:22 | ControlFlowNode for C | import | class C | builtin-class type |
23+
| test.py:22:12:22:12 | test.py:22 | ControlFlowNode for D | import | class D | builtin-class type |
24+
| test.py:25:1:25:1 | test.py:25 | ControlFlowNode for C | import | class C | builtin-class type |
25+
| test.py:25:1:25:3 | test.py:25 | ControlFlowNode for Attribute | import | property p | builtin-class property |
26+
| test.py:26:1:26:1 | test.py:26 | ControlFlowNode for D | import | class D | builtin-class type |
27+
| test.py:26:1:26:3 | test.py:26 | ControlFlowNode for Attribute | import | property q | builtin-class property |
28+
| test.py:27:1:27:1 | test.py:27 | ControlFlowNode for E | import | class E | builtin-class type |
29+
| test.py:27:1:27:3 | test.py:27 | ControlFlowNode for Attribute | import | property p | builtin-class property |
30+
| test.py:28:1:28:1 | test.py:28 | ControlFlowNode for E | import | class E | builtin-class type |
31+
| test.py:28:1:28:3 | test.py:28 | ControlFlowNode for Attribute | import | property q | builtin-class property |
Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,15 @@
11

22
import python
3+
import semmle.python.objects.ObjectInternal
34

5+
string vrepr(Value v) {
6+
/* Work around differing names in 2/3 */
7+
not v = ObjectInternal::boundMethod() and result = v.toString()
8+
or
9+
v = ObjectInternal::boundMethod() and result = "builtin-class method"
10+
}
411

512
from ControlFlowNode f, Context ctx, Value v, ControlFlowNode origin
613
where
714
f.pointsTo(ctx, v, origin)
8-
select f.getLocation(), f.toString(), ctx, v, v.getClass()
15+
select f.getLocation(), f.toString(), ctx, vrepr(v), vrepr(v.getClass())

0 commit comments

Comments
 (0)