Skip to content

Commit e0f7344

Browse files
C++: Imprecise definitions in SSA
1 parent 9726428 commit e0f7344

File tree

14 files changed

+1464
-746
lines changed

14 files changed

+1464
-746
lines changed

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,17 @@ module InstructionSanity {
5050
/**
5151
* Holds if instruction `instr` is missing an expected operand with tag `tag`.
5252
*/
53-
query predicate missingOperand(Instruction instr, OperandTag tag) {
54-
expectsOperand(instr, tag) and
55-
not exists(NonPhiOperand operand |
56-
operand = instr.getAnOperand() and
57-
operand.getOperandTag() = tag
53+
query predicate missingOperand(Instruction instr, string message, FunctionIR func, string funcText) {
54+
exists(OperandTag tag |
55+
expectsOperand(instr, tag) and
56+
not exists(NonPhiOperand operand |
57+
operand = instr.getAnOperand() and
58+
operand.getOperandTag() = tag
59+
) and
60+
message = "Instruction '" + instr.getOpcode().toString() + "' is missing an expected operand with tag '" +
61+
tag.toString() + "' in function '$@'." and
62+
func = instr.getEnclosingFunctionIR() and
63+
funcText = getIdentityString(func.getFunction())
5864
)
5965
}
6066

@@ -302,7 +308,7 @@ class Instruction extends Construction::TInstruction {
302308
result = type
303309
}
304310

305-
private string getResultTypeString() {
311+
string getResultTypeString() {
306312
exists(string valcat |
307313
valcat = getValueCategoryString(getResultType().toString()) and
308314
if (getResultType() instanceof UnknownType and

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll

Lines changed: 83 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,18 @@ import Instruction
33
import IRBlock
44
import cpp
55
import semmle.code.cpp.ir.implementation.MemoryAccessKind
6+
import semmle.code.cpp.ir.internal.Overlap
67
private import semmle.code.cpp.ir.internal.OperandTag
78

89
private newtype TOperand =
9-
TNonPhiOperand(Instruction useInstr, OperandTag tag, Instruction defInstr) {
10-
defInstr = Construction::getInstructionOperandDefinition(useInstr, tag)
10+
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
11+
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag)
1112
} or
12-
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock) {
13-
defInstr = Construction::getPhiInstructionOperandDefinition(useInstr, predecessorBlock)
13+
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
14+
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap)
15+
} or
16+
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
17+
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
1418
}
1519

1620
/**
@@ -25,8 +29,8 @@ class Operand extends TOperand {
2529
result = getUseInstruction().getLocation()
2630
}
2731

28-
final IRFunction getEnclosingIRFunction() {
29-
result = getUseInstruction().getEnclosingIRFunction()
32+
final FunctionIR getEnclosingFunctionIR() {
33+
result = getUseInstruction().getEnclosingFunctionIR()
3034
}
3135

3236
/**
@@ -43,6 +47,20 @@ class Operand extends TOperand {
4347
none()
4448
}
4549

50+
/**
51+
* Gets the overlap relationship between the operand's definition and its use.
52+
*/
53+
Overlap getDefinitionOverlap() {
54+
none()
55+
}
56+
57+
/**
58+
* Holds if the result of the definition instruction does not exactly overlap this use.
59+
*/
60+
final predicate isDefinitionInexact() {
61+
not getDefinitionOverlap() instanceof MustExactlyOverlap
62+
}
63+
4664
/**
4765
* Gets a prefix to use when dumping the operand in an operand list.
4866
*/
@@ -61,6 +79,13 @@ class Operand extends TOperand {
6179
result = getDumpLabel() + getDefinitionInstruction().getResultId()
6280
}
6381

82+
private string getInexactSpecifier() {
83+
if isDefinitionInexact() then
84+
result = "~"
85+
else
86+
result = ""
87+
}
88+
6489
/**
6590
* Get the order in which the operand should be sorted in the operand list.
6691
*/
@@ -104,10 +129,8 @@ class Operand extends TOperand {
104129
*/
105130
class MemoryOperand extends Operand {
106131
MemoryOperand() {
107-
exists(MemoryOperandTag tag |
108-
this = TNonPhiOperand(_, tag, _)
109-
) or
110-
this = TPhiOperand(_, _, _)
132+
this = TNonPhiMemoryOperand(_, _, _, _) or
133+
this = TPhiOperand(_, _, _, _)
111134
}
112135

113136
override predicate isGLValue() {
@@ -133,27 +156,17 @@ class MemoryOperand extends Operand {
133156
}
134157
}
135158

136-
/**
137-
* An operand that consumes a register (non-memory) result.
138-
*/
139-
class RegisterOperand extends Operand {
140-
RegisterOperand() {
141-
exists(RegisterOperandTag tag |
142-
this = TNonPhiOperand(_, tag, _)
143-
)
144-
}
145-
}
146-
147159
/**
148160
* An operand that is not an operand of a `PhiInstruction`.
149161
*/
150-
class NonPhiOperand extends Operand, TNonPhiOperand {
162+
class NonPhiOperand extends Operand {
151163
Instruction useInstr;
152164
Instruction defInstr;
153165
OperandTag tag;
154166

155167
NonPhiOperand() {
156-
this = TNonPhiOperand(useInstr, tag, defInstr)
168+
this = TRegisterOperand(useInstr, tag, defInstr) or
169+
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _)
157170
}
158171

159172
override final Instruction getUseInstruction() {
@@ -177,7 +190,32 @@ class NonPhiOperand extends Operand, TNonPhiOperand {
177190
}
178191
}
179192

180-
class TypedOperand extends NonPhiOperand, MemoryOperand {
193+
/**
194+
* An operand that consumes a register (non-memory) result.
195+
*/
196+
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
197+
override RegisterOperandTag tag;
198+
199+
override final Overlap getDefinitionOverlap() {
200+
// All register results overlap exactly with their uses.
201+
result instanceof MustExactlyOverlap
202+
}
203+
}
204+
205+
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
206+
override MemoryOperandTag tag;
207+
Overlap overlap;
208+
209+
NonPhiMemoryOperand() {
210+
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap)
211+
}
212+
213+
override final Overlap getDefinitionOverlap() {
214+
result = overlap
215+
}
216+
}
217+
218+
class TypedOperand extends NonPhiMemoryOperand {
181219
override TypedOperandTag tag;
182220

183221
override final Type getType() {
@@ -189,7 +227,7 @@ class TypedOperand extends NonPhiOperand, MemoryOperand {
189227
* The address operand of an instruction that loads or stores a value from
190228
* memory (e.g. `Load`, `Store`).
191229
*/
192-
class AddressOperand extends NonPhiOperand, RegisterOperand {
230+
class AddressOperand extends RegisterOperand {
193231
override AddressOperandTag tag;
194232

195233
override string toString() {
@@ -216,7 +254,7 @@ class LoadOperand extends TypedOperand {
216254
/**
217255
* The source value operand of a `Store` instruction.
218256
*/
219-
class StoreValueOperand extends NonPhiOperand, RegisterOperand {
257+
class StoreValueOperand extends RegisterOperand {
220258
override StoreValueOperandTag tag;
221259

222260
override string toString() {
@@ -227,7 +265,7 @@ class StoreValueOperand extends NonPhiOperand, RegisterOperand {
227265
/**
228266
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
229267
*/
230-
class UnaryOperand extends NonPhiOperand, RegisterOperand {
268+
class UnaryOperand extends RegisterOperand {
231269
override UnaryOperandTag tag;
232270

233271
override string toString() {
@@ -238,7 +276,7 @@ class UnaryOperand extends NonPhiOperand, RegisterOperand {
238276
/**
239277
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
240278
*/
241-
class LeftOperand extends NonPhiOperand, RegisterOperand {
279+
class LeftOperand extends RegisterOperand {
242280
override LeftOperandTag tag;
243281

244282
override string toString() {
@@ -249,7 +287,7 @@ class LeftOperand extends NonPhiOperand, RegisterOperand {
249287
/**
250288
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
251289
*/
252-
class RightOperand extends NonPhiOperand, RegisterOperand {
290+
class RightOperand extends RegisterOperand {
253291
override RightOperandTag tag;
254292

255293
override string toString() {
@@ -260,7 +298,7 @@ class RightOperand extends NonPhiOperand, RegisterOperand {
260298
/**
261299
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
262300
*/
263-
class ConditionOperand extends NonPhiOperand, RegisterOperand {
301+
class ConditionOperand extends RegisterOperand {
264302
override ConditionOperandTag tag;
265303

266304
override string toString() {
@@ -272,7 +310,7 @@ class ConditionOperand extends NonPhiOperand, RegisterOperand {
272310
* An operand of the special `UnmodeledUse` instruction, representing a value
273311
* whose set of uses is unknown.
274312
*/
275-
class UnmodeledUseOperand extends NonPhiOperand, MemoryOperand {
313+
class UnmodeledUseOperand extends NonPhiMemoryOperand {
276314
override UnmodeledUseOperandTag tag;
277315

278316
override string toString() {
@@ -287,7 +325,7 @@ class UnmodeledUseOperand extends NonPhiOperand, MemoryOperand {
287325
/**
288326
* The operand representing the target function of an `Call` instruction.
289327
*/
290-
class CallTargetOperand extends NonPhiOperand, RegisterOperand {
328+
class CallTargetOperand extends RegisterOperand {
291329
override CallTargetOperandTag tag;
292330

293331
override string toString() {
@@ -300,7 +338,7 @@ class CallTargetOperand extends NonPhiOperand, RegisterOperand {
300338
* positional arguments (represented by `PositionalArgumentOperand`) and the
301339
* implicit `this` argument, if any (represented by `ThisArgumentOperand`).
302340
*/
303-
class ArgumentOperand extends NonPhiOperand, RegisterOperand {
341+
class ArgumentOperand extends RegisterOperand {
304342
override ArgumentOperandTag tag;
305343
}
306344

@@ -379,13 +417,14 @@ class SideEffectOperand extends TypedOperand {
379417
/**
380418
* An operand of a `PhiInstruction`.
381419
*/
382-
class PhiInputOperand extends MemoryOperand, TPhiOperand {
420+
class PhiOperand extends MemoryOperand, TPhiOperand {
383421
PhiInstruction useInstr;
384422
Instruction defInstr;
385423
IRBlock predecessorBlock;
424+
Overlap overlap;
386425

387-
PhiInputOperand() {
388-
this = TPhiOperand(useInstr, defInstr, predecessorBlock)
426+
PhiOperand() {
427+
this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
389428
}
390429

391430
override string toString() {
@@ -400,6 +439,10 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
400439
result = defInstr
401440
}
402441

442+
override final Overlap getDefinitionOverlap() {
443+
result = overlap
444+
}
445+
403446
override final int getDumpSortOrder() {
404447
result = 11 + getPredecessorBlock().getDisplayIndex()
405448
}
@@ -423,10 +466,8 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
423466
/**
424467
* The total operand of a Chi node, representing the previous value of the memory.
425468
*/
426-
class ChiTotalOperand extends MemoryOperand {
427-
ChiTotalOperand() {
428-
this = TNonPhiOperand(_, chiTotalOperand(), _)
429-
}
469+
class ChiTotalOperand extends NonPhiMemoryOperand {
470+
override ChiTotalOperandTag tag;
430471

431472
override string toString() {
432473
result = "ChiTotal"
@@ -441,10 +482,8 @@ class ChiTotalOperand extends MemoryOperand {
441482
/**
442483
* The partial operand of a Chi node, representing the value being written to part of the memory.
443484
*/
444-
class ChiPartialOperand extends MemoryOperand {
445-
ChiPartialOperand() {
446-
this = TNonPhiOperand(_, chiPartialOperand(), _)
447-
}
485+
class ChiPartialOperand extends NonPhiMemoryOperand {
486+
override ChiPartialOperandTag tag;
448487

449488
override string toString() {
450489
result = "ChiPartial"

0 commit comments

Comments
 (0)