Skip to content

Commit 9fae2fa

Browse files
author
Dave Bartolomeo
authored
Merge pull request github#2994 from jbj/IRSanity-separate-file
C++: Move InstructionSanity out of Instruction.qll
2 parents 155985c + a13f355 commit 9fae2fa

File tree

10 files changed

+1370
-1350
lines changed

10 files changed

+1370
-1350
lines changed
Lines changed: 274 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,275 @@
11
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

Comments
 (0)