11private 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