-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathSpecialMethods.qll
More file actions
120 lines (99 loc) · 3.87 KB
/
SpecialMethods.qll
File metadata and controls
120 lines (99 loc) · 3.87 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* Provides support for special methods.
* This is done in two steps:
* - A subset of `ControlFlowNode`s are labelled as potentially corresponding to
* a special method call (by being an instance of `SpecialMethod::Potential`).
* - A subset of the potential special method calls are labelled as being actual
* special method calls (`SpecialMethodCallNode`) if the appropriate method is defined.
* Extend `SpecialMethod::Potential` to capture more cases.
*/
private import python
private import LegacyPointsTo
/** A control flow node which might correspond to a special method call. */
class PotentialSpecialMethodCallNode extends ControlFlowNode instanceof SpecialMethod::Potential { }
/**
* Machinery for detecting special method calls.
* Extend `SpecialMethod::Potential` to capture more cases.
*/
module SpecialMethod {
/** A control flow node which might correspond to a special method call. */
abstract class Potential extends ControlFlowNode {
/** Gets the name of the method that would be called. */
abstract string getSpecialMethodName();
/** Gets the control flow node that would be passed as the specified argument. */
abstract ControlFlowNode getArg(int n);
/**
* Gets the control flow node corresponding to the instance
* that would define the special method.
*/
ControlFlowNode getSelf() { result = this.getArg(0) }
}
/** A binary expression node that might correspond to a special method call. */
class SpecialBinOp extends Potential, BinaryExprNode {
Operator operator;
SpecialBinOp() { this.getOp() = operator }
override string getSpecialMethodName() { result = operator.getSpecialMethodName() }
override ControlFlowNode getArg(int n) {
n = 0 and result = this.getLeft()
or
n = 1 and result = this.getRight()
}
}
/** A subscript expression node that might correspond to a special method call. */
abstract class SpecialSubscript extends Potential, SubscriptNode {
override ControlFlowNode getArg(int n) {
n = 0 and result = this.getObject()
or
n = 1 and result = this.getIndex()
}
}
/** A subscript expression node that might correspond to a call to __getitem__. */
class SpecialGetItem extends SpecialSubscript {
SpecialGetItem() { this.isLoad() }
override string getSpecialMethodName() { result = "__getitem__" }
}
/** A subscript expression node that might correspond to a call to __setitem__. */
class SpecialSetItem extends SpecialSubscript {
SpecialSetItem() { this.isStore() }
override string getSpecialMethodName() { result = "__setitem__" }
override ControlFlowNode getArg(int n) {
n = 0 and result = this.getObject()
or
n = 1 and result = this.getIndex()
or
n = 2 and result = this.getValueNode()
}
private ControlFlowNode getValueNode() {
exists(AssignStmt a |
a.getATarget() = this.getNode() and
result.getNode() = a.getValue()
)
or
exists(AugAssign a |
a.getTarget() = this.getNode() and
result.getNode() = a.getValue()
)
}
}
/** A subscript expression node that might correspond to a call to __delitem__. */
class SpecialDelItem extends SpecialSubscript {
SpecialDelItem() { this.isDelete() }
override string getSpecialMethodName() { result = "__delitem__" }
}
}
/** A control flow node corresponding to a special method call. */
class SpecialMethodCallNode extends PotentialSpecialMethodCallNode {
Value resolvedSpecialMethod;
SpecialMethodCallNode() {
exists(SpecialMethod::Potential pot |
this = pot and
pot.getSelf()
.(ControlFlowNodeWithPointsTo)
.pointsTo()
.getClass()
.lookup(pot.getSpecialMethodName()) = resolvedSpecialMethod
)
}
/** Gets the method that is called. */
Value getResolvedSpecialMethod() { result = resolvedSpecialMethod }
}