-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathInstructionGroups.qll
More file actions
260 lines (201 loc) · 7.9 KB
/
InstructionGroups.qll
File metadata and controls
260 lines (201 loc) · 7.9 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
/**
* Provides classes representing various classes of expression
* and other instructions.
*/
private import CIL
private import dotnet
/**
* An instruction that pushes a value onto the stack.
*/
class Expr extends DotNet::Expr, Instruction, @cil_expr {
override int getPushCount() { result = 1 }
override Type getType() { result = Instruction.super.getType() }
override Method getEnclosingCallable() { result = getImplementation().getMethod() }
/**
* The "parent" of a CIL expression is taken to be the instruction
* that consumes the value pushed by this instruction.
*/
override Expr getParent() { this = result.getAnOperand() }
}
/** An instruction that changes control flow. */
class Branch extends Instruction, @cil_jump {
/** Gets the instruction that is jumped to. */
Instruction getTarget() { cil_jump(this, result) }
override string getExtra() { result = getTarget().getIndex() + ":" }
}
/** An instruction that unconditionally jumps to another instruction. */
class UnconditionalBranch extends Branch, @cil_unconditional_jump {
override Instruction getASuccessorType(FlowType t) {
t instanceof NormalFlow and result = getTarget()
}
override predicate canFlowNext() { none() }
}
/** An instruction that jumps to a target based on a condition. */
class ConditionalBranch extends Branch, @cil_conditional_jump {
override Instruction getASuccessorType(FlowType t) {
t instanceof TrueFlow and result = getTarget()
or
t instanceof FalseFlow and result = getImplementation().getInstruction(getIndex() + 1)
}
override int getPushCount() { result = 0 }
}
/** An expression with two operands. */
class BinaryExpr extends Expr, @cil_binary_expr {
override int getPopCount() { result = 2 }
}
/** An expression with one operand. */
class UnaryExpr extends Expr, @cil_unary_expr {
override int getPopCount() { result = 1 }
/** Gets the operand of this unary expression. */
Expr getOperand() { result = getOperand(0) }
}
/** A binary expression that compares two values. */
class ComparisonOperation extends BinaryExpr, @cil_comparison_operation {
override BoolType getType() { exists(result) }
}
/** A binary arithmetic expression. */
class BinaryArithmeticExpr extends BinaryExpr, @cil_binary_arithmetic_operation {
override Type getType() {
exists(Type t0, Type t1 |
t0 = getOperand(0).getType().getUnderlyingType() and
t1 = getOperand(1).getType().getUnderlyingType()
|
t0 = t1 and result = t0
or
t0.getConversionIndex() < t1.getConversionIndex() and result = t1
or
t0.getConversionIndex() > t1.getConversionIndex() and result = t0
)
}
}
/** A binary bitwise expression. */
class BinaryBitwiseOperation extends BinaryExpr, @cil_binary_bitwise_operation {
// This is wrong but efficient - should depend on the types of the operands.
override IntType getType() { exists(result) }
}
/** A unary bitwise expression. */
class UnaryBitwiseOperation extends UnaryExpr, @cil_unary_bitwise_operation {
// This is wrong but efficient - should depend on the types of the operands.
override IntType getType() { exists(result) }
}
/** A unary expression that converts a value from one primitive type to another. */
class Conversion extends UnaryExpr, @cil_conversion_operation {
/** Gets the expression being converted. */
Expr getExpr() { result = getOperand(0) }
}
/** A branch that leaves the scope of a `Handler`. */
class Leave extends UnconditionalBranch, @cil_leave_any { }
/** An expression that pushes a literal value onto the stack. */
class Literal extends DotNet::Literal, Expr, @cil_literal {
/** Gets the pushed value. */
override string getValue() { cil_value(this, result) }
override string getExtra() { result = getValue() }
}
/** An integer literal. */
class IntLiteral extends Literal, @cil_ldc_i {
override string getExtra() { none() }
override IntType getType() { exists(result) }
}
/** An expression that pushes a `float`/`Single`. */
class FloatLiteral extends Literal, @cil_ldc_r { }
/** An expression that pushes a `null` value onto the stack. */
class NullLiteral extends Literal, @cil_ldnull { }
/** An expression that pushes a string onto the stack. */
class StringLiteral extends Literal, @cil_ldstr { }
/** A branch with one operand. */
class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
override int getPopCount() { result = 1 }
override int getPushCount() { result = 0 }
}
/** A branch with two operands. */
class BinaryBranch extends ConditionalBranch, @cil_binary_jump {
override int getPopCount() { result = 2 }
override int getPushCount() { result = 0 }
}
/** A call. */
class Call extends Expr, DotNet::Call, @cil_call_any {
/** Gets the method that is called. */
override Method getTarget() { cil_access(this, result) }
override Method getARuntimeTarget() { result = getTarget().getAnOverrider*() }
override string getExtra() { result = getTarget().getQualifiedName() }
/**
* Gets the return type of the call. Methods that do not return a value
* return the `void` type, `System.Void`, although the value of `getPushCount` is
* 0 in this case.
*/
override Type getType() { result = getTarget().getReturnType() }
// The number of items popped/pushed from the stack
// depends on the target of the call.
override int getPopCount() { result = getTarget().getCallPopCount() }
override int getPushCount() { result = getTarget().getCallPushCount() }
/**
* Holds if this is a "tail call", meaning that control does not return to the
* calling method.
*/
predicate isTailCall() {
getImplementation().getInstruction(getIndex() - 1) instanceof Opcodes::Tail
}
/** Holds if this call is virtual and could go to an overriding method. */
predicate isVirtual() { none() }
override Expr getRawArgument(int i) { result = getOperand(getPopCount() - i - 1) }
/** Gets the qualifier of this call, if any. */
Expr getQualifier() { result = getRawArgument(0) and not getTarget().isStatic() }
override Expr getArgument(int i) {
if getTarget().isStatic()
then result = getRawArgument(i)
else (
result = getRawArgument(i + 1) and i >= 0
)
}
override Expr getArgumentForParameter(DotNet::Parameter param) {
exists(int index |
result = this.getRawArgument(index) and param = this.getTarget().getRawParameter(index)
)
}
}
/** A tail call. */
class TailCall extends Call {
TailCall() { this.isTailCall() }
override predicate canFlowNext() { none() }
}
/** A call to a static target. */
class StaticCall extends Call {
StaticCall() { not this.isVirtual() }
}
/** A call to a virtual target. */
class VirtualCall extends Call {
VirtualCall() { this.isVirtual() }
}
/** A read of an array element. */
class ReadArrayElement extends BinaryExpr, @cil_read_array {
/** Gets the array being read. */
Expr getArray() { result = getOperand(1) }
/** Gets the index into the array. */
Expr getArrayIndex() { result = getOperand(0) }
}
/** A write of an array element. */
class WriteArrayElement extends Instruction, @cil_write_array {
override int getPushCount() { result = 0 }
override int getPopCount() { result = 3 }
}
/** A `return` statement. */
class Return extends Instruction, @cil_ret {
/** Gets the expression being returned, if any. */
Expr getExpr() { result = getOperand(0) }
override predicate canFlowNext() { none() }
}
/** A `throw` statement. */
class Throw extends Instruction, DotNet::Throw, @cil_throw_any {
override Expr getExpr() { result = getOperand(0) }
override predicate canFlowNext() { none() }
}
/** Stores a value at an address/location. */
class StoreIndirect extends Instruction, @cil_stind {
override int getPopCount() { result = 2 }
/** Gets the location to store the value at. */
Expr getAddress() { result = getOperand(1) }
/** Gets the value to store. */
Expr getExpr() { result = getOperand(0) }
}
/** Loads a value from an address/location. */
class LoadIndirect extends UnaryExpr, @cil_ldind { }