-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathMethod.qll
More file actions
285 lines (214 loc) · 9.81 KB
/
Method.qll
File metadata and controls
285 lines (214 loc) · 9.81 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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
/**
* Provides classes for methods.
*
* Methods and implementations are different because there can be several implementations for the same
* method in different assemblies. It is not really possible to guarantee which methods will be loaded
* at run-time.
*/
private import CIL
private import dotnet
/**
* An implementation of a method in an assembly.
*/
class MethodImplementation extends EntryPoint, @cil_method_implementation {
/** Gets the method of this implementation. */
Method getMethod() { cil_method_implementation(this, result, _) }
override MethodImplementation getImplementation() { result = this }
/** Gets the location of this implementation. */
override Assembly getLocation() { cil_method_implementation(this, _, result) }
/** Gets the instruction at index `index`. */
Instruction getInstruction(int index) { cil_instruction(result, _, index, this) }
/** Gets the `n`th local variable of this implementation. */
LocalVariable getLocalVariable(int n) { cil_local_variable(result, this, n, _) }
/** Gets a local variable of this implementation, if any. */
LocalVariable getALocalVariable() { result = getLocalVariable(_) }
/** Gets an instruction in this implementation, if any. */
Instruction getAnInstruction() { result = getInstruction(_) }
/** Gets the total number of instructions in this implementation. */
int getNumberOfInstructions() { result = count(getAnInstruction()) }
/** Gets the `i`th handler in this implementation. */
Handler getHandler(int i) { result.getImplementation() = this and result.getIndex() = i }
/** Gets a handler in this implementation, if any. */
Handler getAHandler() { result.getImplementation() = this }
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and result.getImplementation() = this and result.getIndex() = 0
}
/** Gets the maximum stack size of this implementation. */
int getStackSize() { cil_method_stack_size(this, result) }
override string toString() { result = getMethod().toString() }
/** Gets a string representing the disassembly of this implementation. */
string getDisassembly() {
result =
concat(Instruction i |
i = this.getAnInstruction()
|
i.toStringExtra(), ", " order by i.getIndex()
)
}
}
/**
* A method, which corresponds to any callable in C#, including constructors,
* destructors, operators, accessors and so on.
*/
class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowNode,
CustomModifierReceiver, Parameterizable, @cil_method {
/**
* Gets a method implementation, if any. Note that there can
* be several implementations in different assemblies.
*/
MethodImplementation getAnImplementation() { result.getMethod() = this }
/** Gets the "best" implementation of this method, if any. */
BestImplementation getImplementation() { result = getAnImplementation() }
override Method getMethod() { result = this }
override string getName() { cil_method(this, result, _, _) }
override string toString() { result = this.getName() }
override Type getDeclaringType() { cil_method(this, _, result, _) }
override Location getLocation() { result = Element.super.getLocation() }
override Location getALocation() { cil_method_location(this.getUnboundDeclaration(), result) }
override MethodParameter getParameter(int n) {
if isStatic() then result = getRawParameter(n) else (result = getRawParameter(n + 1) and n >= 0)
}
override Type getType() { result = getReturnType() }
/** Gets the return type of this method. */
override Type getReturnType() { cil_method(this, _, _, result) }
/** Holds if the return type is `void`. */
predicate returnsVoid() { getReturnType() instanceof VoidType }
/** Gets the number of stack items pushed in a call to this method. */
int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 }
/** Gets the number of stack items popped in a call to this method. */
int getCallPopCount() { result = count(getRawParameter(_)) }
/** Gets a method called by this method. */
Method getACallee() { result = getImplementation().getAnInstruction().(Call).getTarget() }
/** Holds if this method is `virtual`. */
predicate isVirtual() { cil_virtual(this) }
/** Holds if the name of this method is special, for example an operator. */
predicate isSpecial() { cil_specialname(this) }
/** Holds of this method is marked as secure. */
predicate isSecureObject() { cil_requiresecobject(this) }
/** Holds if the method does not override an existing method. */
predicate isNew() { cil_newslot(this) }
override predicate isStatic() { cil_static(this) }
/** Gets the unbound declaration of this method, or the method itself. */
Method getUnboundMethod() { cil_method_source_declaration(this, result) }
override Method getUnboundDeclaration() { result = getUnboundMethod() }
/** Holds if this method is an instance constructor. */
predicate isInstanceConstructor() { isSpecial() and getName() = ".ctor" }
/** Holds if this method is a static class constructor. */
predicate isStaticConstructor() { isSpecial() and getName() = ".cctor" }
/** Holds if this method is a constructor (static or instance). */
predicate isConstructor() { isStaticConstructor() or isInstanceConstructor() }
/** Holds if this method is a destructor/finalizer. */
predicate isFinalizer() { getOverriddenMethod*().getQualifiedName() = "System.Object.Finalize" }
/** Holds if this method is an operator. */
predicate isOperator() { isSpecial() and getName().matches("op\\_%") }
/** Holds if this method is a getter. */
predicate isGetter() { isSpecial() and getName().matches("get\\_%") }
/** Holds if this method is a setter. */
predicate isSetter() { isSpecial() and getName().matches("set\\_%") }
/** Holds if this method is an adder/add event accessor. */
predicate isAdder() { isSpecial() and getName().matches("add\\_%") }
/** Holds if this method is a remover/remove event accessor. */
predicate isRemove() { isSpecial() and getName().matches("remove\\_%") }
/** Holds if this method is an implicit conversion operator. */
predicate isImplicitConversion() { isSpecial() and getName() = "op_Implicit" }
/** Holds if this method is an explicit conversion operator. */
predicate isExplicitConversion() { isSpecial() and getName() = "op_Explicit" }
/** Holds if this method is a conversion operator. */
predicate isConversion() { isImplicitConversion() or isExplicitConversion() }
/**
* Gets a method that is overridden, either in a base class
* or in an interface.
*/
Method getOverriddenMethod() { cil_implements(this, result) }
/** Gets a method that overrides this method, if any. */
final Method getAnOverrider() { result.getOverriddenMethod() = this }
override predicate hasBody() { exists(getImplementation()) }
override predicate canReturn(DotNet::Expr expr) {
exists(Return ret | ret.getImplementation() = this.getImplementation() and expr = ret.getExpr())
}
}
/** A destructor/finalizer. */
class Destructor extends Method, DotNet::Destructor {
Destructor() { this.isFinalizer() }
}
/** A constructor. */
class Constructor extends Method, DotNet::Constructor {
Constructor() { this.isConstructor() }
}
/** A static/class constructor. */
class StaticConstructor extends Constructor {
StaticConstructor() { this.isStaticConstructor() }
}
/** An instance constructor. */
class InstanceConstructor extends Constructor {
InstanceConstructor() { this.isInstanceConstructor() }
}
/** A method that always returns the `this` parameter. */
class ChainingMethod extends Method {
ChainingMethod() {
forex(Return ret | ret = getImplementation().getAnInstruction() |
ret.getExpr() instanceof ThisAccess
)
}
}
/** An accessor. */
abstract class Accessor extends Method {
/** Gets the property declaring this accessor. */
abstract Property getProperty();
}
/** A getter. */
class Getter extends Accessor {
Getter() { cil_getter(_, this) }
override Property getProperty() { cil_getter(result, this) }
}
/**
* A method that does nothing but retrieve a field.
* Note that this is not necessarily a property getter.
*/
class TrivialGetter extends Method {
TrivialGetter() {
exists(MethodImplementation impl | impl = getAnImplementation() |
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1) instanceof FieldReadAccess and
impl.getInstruction(2) instanceof Return
)
}
/** Gets the underlying field of this getter. */
Field getField() { getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result }
}
/** A setter. */
class Setter extends Accessor {
Setter() { cil_setter(_, this) }
override Property getProperty() { cil_setter(result, this) }
/** Holds if this setter is an `init` accessor. */
predicate isInitOnly() {
exists(Type t | t.getQualifiedName() = "System.Runtime.CompilerServices.IsExternalInit" |
this.hasRequiredCustomModifier(t)
)
}
}
/**
* A method that does nothing but set a field.
* This is not necessarily a property setter.
*/
class TrivialSetter extends Method {
TrivialSetter() {
exists(MethodImplementation impl | impl = getImplementation() |
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and
impl.getInstruction(2) instanceof FieldWriteAccess
)
}
/** Gets the underlying field of this setter. */
Field getField() {
result = getImplementation().getAnInstruction().(FieldWriteAccess).getTarget()
}
}
/** An alias for `Method` for compatibility with the C# data model. */
class Callable = Method;
/** An operator. */
class Operator extends Method {
Operator() { this.isOperator() }
/** Gets the name of the implementing method (for compatibility with C# data model). */
string getFunctionName() { result = getName() }
}