1
1
private import IR
2
- import InstructionSanity
3
- import IRTypeSanity
2
+ import InstructionSanity // module is below
3
+ import IRTypeSanity // module is in IRType.qll
4
+
5
+ module InstructionSanity {
6
+ private import internal.InstructionImports as Imports
7
+ private import Imports:: OperandTag
8
+ private import internal.IRInternal
9
+
10
+ /**
11
+ * Holds if instruction `instr` is missing an expected operand with tag `tag`.
12
+ */
13
+ query predicate missingOperand ( Instruction instr , string message , IRFunction func , string funcText ) {
14
+ exists ( OperandTag tag |
15
+ instr .getOpcode ( ) .hasOperand ( tag ) and
16
+ not exists ( NonPhiOperand operand |
17
+ operand = instr .getAnOperand ( ) and
18
+ operand .getOperandTag ( ) = tag
19
+ ) and
20
+ message =
21
+ "Instruction '" + instr .getOpcode ( ) .toString ( ) +
22
+ "' is missing an expected operand with tag '" + tag .toString ( ) + "' in function '$@'." and
23
+ func = instr .getEnclosingIRFunction ( ) and
24
+ funcText = Language:: getIdentityString ( func .getFunction ( ) )
25
+ )
26
+ }
27
+
28
+ /**
29
+ * Holds if instruction `instr` has an unexpected operand with tag `tag`.
30
+ */
31
+ query predicate unexpectedOperand ( Instruction instr , OperandTag tag ) {
32
+ exists ( NonPhiOperand operand |
33
+ operand = instr .getAnOperand ( ) and
34
+ operand .getOperandTag ( ) = tag
35
+ ) and
36
+ not instr .getOpcode ( ) .hasOperand ( tag ) and
37
+ not ( instr instanceof CallInstruction and tag instanceof ArgumentOperandTag ) and
38
+ not (
39
+ instr instanceof BuiltInOperationInstruction and tag instanceof PositionalArgumentOperandTag
40
+ ) and
41
+ not ( instr instanceof InlineAsmInstruction and tag instanceof AsmOperandTag )
42
+ }
43
+
44
+ /**
45
+ * Holds if instruction `instr` has multiple operands with tag `tag`.
46
+ */
47
+ query predicate duplicateOperand (
48
+ Instruction instr , string message , IRFunction func , string funcText
49
+ ) {
50
+ exists ( OperandTag tag , int operandCount |
51
+ operandCount =
52
+ strictcount ( NonPhiOperand operand |
53
+ operand = instr .getAnOperand ( ) and
54
+ operand .getOperandTag ( ) = tag
55
+ ) and
56
+ operandCount > 1 and
57
+ not tag instanceof UnmodeledUseOperandTag and
58
+ message =
59
+ "Instruction has " + operandCount + " operands with tag '" + tag .toString ( ) + "'" +
60
+ " in function '$@'." and
61
+ func = instr .getEnclosingIRFunction ( ) and
62
+ funcText = Language:: getIdentityString ( func .getFunction ( ) )
63
+ )
64
+ }
65
+
66
+ /**
67
+ * Holds if `Phi` instruction `instr` is missing an operand corresponding to
68
+ * the predecessor block `pred`.
69
+ */
70
+ query predicate missingPhiOperand ( PhiInstruction instr , IRBlock pred ) {
71
+ pred = instr .getBlock ( ) .getAPredecessor ( ) and
72
+ not exists ( PhiInputOperand operand |
73
+ operand = instr .getAnOperand ( ) and
74
+ operand .getPredecessorBlock ( ) = pred
75
+ )
76
+ }
77
+
78
+ query predicate missingOperandType ( Operand operand , string message ) {
79
+ exists ( Language:: Function func , Instruction use |
80
+ not exists ( operand .getType ( ) ) and
81
+ use = operand .getUse ( ) and
82
+ func = use .getEnclosingFunction ( ) and
83
+ message =
84
+ "Operand '" + operand .toString ( ) + "' of instruction '" + use .getOpcode ( ) .toString ( ) +
85
+ "' missing type in function '" + Language:: getIdentityString ( func ) + "'."
86
+ )
87
+ }
88
+
89
+ query predicate duplicateChiOperand (
90
+ ChiInstruction chi , string message , IRFunction func , string funcText
91
+ ) {
92
+ chi .getTotal ( ) = chi .getPartial ( ) and
93
+ message =
94
+ "Chi instruction for " + chi .getPartial ( ) .toString ( ) +
95
+ " has duplicate operands in function $@" and
96
+ func = chi .getEnclosingIRFunction ( ) and
97
+ funcText = Language:: getIdentityString ( func .getFunction ( ) )
98
+ }
99
+
100
+ query predicate sideEffectWithoutPrimary (
101
+ SideEffectInstruction instr , string message , IRFunction func , string funcText
102
+ ) {
103
+ not exists ( instr .getPrimaryInstruction ( ) ) and
104
+ message = "Side effect instruction missing primary instruction in function $@" and
105
+ func = instr .getEnclosingIRFunction ( ) and
106
+ funcText = Language:: getIdentityString ( func .getFunction ( ) )
107
+ }
108
+
109
+ /**
110
+ * Holds if an instruction, other than `ExitFunction`, has no successors.
111
+ */
112
+ query predicate instructionWithoutSuccessor ( Instruction instr ) {
113
+ not exists ( instr .getASuccessor ( ) ) and
114
+ not instr instanceof ExitFunctionInstruction and
115
+ // Phi instructions aren't linked into the instruction-level flow graph.
116
+ not instr instanceof PhiInstruction and
117
+ not instr instanceof UnreachedInstruction
118
+ }
119
+
120
+ /**
121
+ * Holds if there are multiple (`n`) edges of kind `kind` from `source`,
122
+ * where `target` is among the targets of those edges.
123
+ */
124
+ query predicate ambiguousSuccessors ( Instruction source , EdgeKind kind , int n , Instruction target ) {
125
+ n = strictcount ( Instruction t | source .getSuccessor ( kind ) = t ) and
126
+ n > 1 and
127
+ source .getSuccessor ( kind ) = target
128
+ }
129
+
130
+ /**
131
+ * Holds if `instr` in `f` is part of a loop even though the AST of `f`
132
+ * contains no element that can cause loops.
133
+ */
134
+ query predicate unexplainedLoop ( Language:: Function f , Instruction instr ) {
135
+ exists ( IRBlock block |
136
+ instr .getBlock ( ) = block and
137
+ block .getEnclosingFunction ( ) = f and
138
+ block .getASuccessor + ( ) = block
139
+ ) and
140
+ not Language:: hasPotentialLoop ( f )
141
+ }
142
+
143
+ /**
144
+ * Holds if a `Phi` instruction is present in a block with fewer than two
145
+ * predecessors.
146
+ */
147
+ query predicate unnecessaryPhiInstruction ( PhiInstruction instr ) {
148
+ count ( instr .getBlock ( ) .getAPredecessor ( ) ) < 2
149
+ }
150
+
151
+ /**
152
+ * Holds if operand `operand` consumes a value that was defined in
153
+ * a different function.
154
+ */
155
+ query predicate operandAcrossFunctions ( Operand operand , Instruction instr , Instruction defInstr ) {
156
+ operand .getUse ( ) = instr and
157
+ operand .getAnyDef ( ) = defInstr and
158
+ instr .getEnclosingIRFunction ( ) != defInstr .getEnclosingIRFunction ( )
159
+ }
160
+
161
+ /**
162
+ * Holds if instruction `instr` is not in exactly one block.
163
+ */
164
+ query predicate instructionWithoutUniqueBlock ( Instruction instr , int blockCount ) {
165
+ blockCount = count ( instr .getBlock ( ) ) and
166
+ blockCount != 1
167
+ }
168
+
169
+ private predicate forwardEdge ( IRBlock b1 , IRBlock b2 ) {
170
+ b1 .getASuccessor ( ) = b2 and
171
+ not b1 .getBackEdgeSuccessor ( _) = b2
172
+ }
173
+
174
+ /**
175
+ * Holds if `f` contains a loop in which no edge is a back edge.
176
+ *
177
+ * This check ensures we don't have too _few_ back edges.
178
+ */
179
+ query predicate containsLoopOfForwardEdges ( IRFunction f ) {
180
+ exists ( IRBlock block |
181
+ forwardEdge + ( block , block ) and
182
+ block .getEnclosingIRFunction ( ) = f
183
+ )
184
+ }
185
+
186
+ /**
187
+ * Holds if `block` is reachable from its function entry point but would not
188
+ * be reachable by traversing only forward edges. This check is skipped for
189
+ * functions containing `goto` statements as the property does not generally
190
+ * hold there.
191
+ *
192
+ * This check ensures we don't have too _many_ back edges.
193
+ */
194
+ query predicate lostReachability ( IRBlock block ) {
195
+ exists ( IRFunction f , IRBlock entry |
196
+ entry = f .getEntryBlock ( ) and
197
+ entry .getASuccessor + ( ) = block and
198
+ not forwardEdge + ( entry , block ) and
199
+ not Language:: hasGoto ( f .getFunction ( ) )
200
+ )
201
+ }
202
+
203
+ /**
204
+ * Holds if the number of back edges differs between the `Instruction` graph
205
+ * and the `IRBlock` graph.
206
+ */
207
+ query predicate backEdgeCountMismatch ( Language:: Function f , int fromInstr , int fromBlock ) {
208
+ fromInstr =
209
+ count ( Instruction i1 , Instruction i2 |
210
+ i1 .getEnclosingFunction ( ) = f and i1 .getBackEdgeSuccessor ( _) = i2
211
+ ) and
212
+ fromBlock =
213
+ count ( IRBlock b1 , IRBlock b2 |
214
+ b1 .getEnclosingFunction ( ) = f and b1 .getBackEdgeSuccessor ( _) = b2
215
+ ) and
216
+ fromInstr != fromBlock
217
+ }
218
+
219
+ /**
220
+ * Gets the point in the function at which the specified operand is evaluated. For most operands,
221
+ * this is at the instruction that consumes the use. For a `PhiInputOperand`, the effective point
222
+ * of evaluation is at the end of the corresponding predecessor block.
223
+ */
224
+ private predicate pointOfEvaluation ( Operand operand , IRBlock block , int index ) {
225
+ block = operand .( PhiInputOperand ) .getPredecessorBlock ( ) and
226
+ index = block .getInstructionCount ( )
227
+ or
228
+ exists ( Instruction use |
229
+ use = operand .( NonPhiOperand ) .getUse ( ) and
230
+ block .getInstruction ( index ) = use
231
+ )
232
+ }
233
+
234
+ /**
235
+ * Holds if `useOperand` has a definition that does not dominate the use.
236
+ */
237
+ query predicate useNotDominatedByDefinition (
238
+ Operand useOperand , string message , IRFunction func , string funcText
239
+ ) {
240
+ exists ( IRBlock useBlock , int useIndex , Instruction defInstr , IRBlock defBlock , int defIndex |
241
+ not useOperand .getUse ( ) instanceof UnmodeledUseInstruction and
242
+ not defInstr instanceof UnmodeledDefinitionInstruction and
243
+ pointOfEvaluation ( useOperand , useBlock , useIndex ) and
244
+ defInstr = useOperand .getAnyDef ( ) and
245
+ (
246
+ defInstr instanceof PhiInstruction and
247
+ defBlock = defInstr .getBlock ( ) and
248
+ defIndex = - 1
249
+ or
250
+ defBlock .getInstruction ( defIndex ) = defInstr
251
+ ) and
252
+ not (
253
+ defBlock .strictlyDominates ( useBlock )
254
+ or
255
+ defBlock = useBlock and
256
+ defIndex < useIndex
257
+ ) and
258
+ message =
259
+ "Operand '" + useOperand .toString ( ) +
260
+ "' is not dominated by its definition in function '$@'." and
261
+ func = useOperand .getEnclosingIRFunction ( ) and
262
+ funcText = Language:: getIdentityString ( func .getFunction ( ) )
263
+ )
264
+ }
265
+
266
+ query predicate switchInstructionWithoutDefaultEdge (
267
+ SwitchInstruction switchInstr , string message , IRFunction func , string funcText
268
+ ) {
269
+ not exists ( switchInstr .getDefaultSuccessor ( ) ) and
270
+ message =
271
+ "SwitchInstruction " + switchInstr .toString ( ) + " without a DefaultEdge in function '$@'." and
272
+ func = switchInstr .getEnclosingIRFunction ( ) and
273
+ funcText = Language:: getIdentityString ( func .getFunction ( ) )
274
+ }
275
+ }
0 commit comments