Skip to content

Commit a42d80a

Browse files
authored
Merge pull request github#3481 from dbartol/github/codeql-c-analysis-team/69
C++/C#: Allow memory operands to lack a definition
2 parents 4f00e40 + 96c87b3 commit a42d80a

File tree

9 files changed

+429
-266
lines changed

9 files changed

+429
-266
lines changed

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

Lines changed: 84 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,66 @@ private newtype TOperand =
1414
not Construction::isInCycle(useInstr) and
1515
strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1
1616
} or
17-
TNonPhiMemoryOperand(
18-
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
19-
) {
20-
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
21-
not Construction::isInCycle(useInstr) and
22-
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
17+
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
18+
useInstr.getOpcode().hasOperand(tag)
2319
} or
2420
TPhiOperand(
2521
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
2622
) {
2723
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
2824
}
2925

26+
/**
27+
* Base class for all register operands. This is a placeholder for the IPA union type that we will
28+
* eventually use for this purpose.
29+
*/
30+
private class RegisterOperandBase extends TRegisterOperand {
31+
/** Gets a textual representation of this element. */
32+
abstract string toString();
33+
}
34+
35+
/**
36+
* Returns the register operand with the specified parameters.
37+
*/
38+
private RegisterOperandBase registerOperand(
39+
Instruction useInstr, RegisterOperandTag tag, Instruction defInstr
40+
) {
41+
result = TRegisterOperand(useInstr, tag, defInstr)
42+
}
43+
44+
/**
45+
* Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we
46+
* will eventually use for this purpose.
47+
*/
48+
private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand {
49+
/** Gets a textual representation of this element. */
50+
abstract string toString();
51+
}
52+
53+
/**
54+
* Returns the non-Phi memory operand with the specified parameters.
55+
*/
56+
private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) {
57+
result = TNonPhiMemoryOperand(useInstr, tag)
58+
}
59+
60+
/**
61+
* Base class for all Phi operands. This is a placeholder for the IPA union type that we will
62+
* eventually use for this purpose.
63+
*/
64+
private class PhiOperandBase extends TPhiOperand {
65+
abstract string toString();
66+
}
67+
68+
/**
69+
* Returns the Phi operand with the specified parameters.
70+
*/
71+
private PhiOperandBase phiOperand(
72+
Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
73+
) {
74+
result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap)
75+
}
76+
3077
/**
3178
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
3279
*/
@@ -165,8 +212,8 @@ class Operand extends TOperand {
165212
*/
166213
class MemoryOperand extends Operand {
167214
MemoryOperand() {
168-
this = TNonPhiMemoryOperand(_, _, _, _) or
169-
this = TPhiOperand(_, _, _, _)
215+
this instanceof NonPhiMemoryOperandBase or
216+
this instanceof PhiOperandBase
170217
}
171218

172219
/**
@@ -200,18 +247,15 @@ class MemoryOperand extends Operand {
200247
*/
201248
class NonPhiOperand extends Operand {
202249
Instruction useInstr;
203-
Instruction defInstr;
204250
OperandTag tag;
205251

206252
NonPhiOperand() {
207-
this = TRegisterOperand(useInstr, tag, defInstr) or
208-
this = TNonPhiMemoryOperand(useInstr, tag, defInstr, _)
253+
this = registerOperand(useInstr, tag, _) or
254+
this = nonPhiMemoryOperand(useInstr, tag)
209255
}
210256

211257
final override Instruction getUse() { result = useInstr }
212258

213-
final override Instruction getAnyDef() { result = defInstr }
214-
215259
final override string getDumpLabel() { result = tag.getLabel() }
216260

217261
final override int getDumpSortOrder() { result = tag.getSortOrder() }
@@ -222,22 +266,41 @@ class NonPhiOperand extends Operand {
222266
/**
223267
* An operand that consumes a register (non-memory) result.
224268
*/
225-
class RegisterOperand extends NonPhiOperand, TRegisterOperand {
269+
class RegisterOperand extends NonPhiOperand, RegisterOperandBase {
226270
override RegisterOperandTag tag;
271+
Instruction defInstr;
272+
273+
RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) }
274+
275+
final override string toString() { result = tag.toString() }
276+
277+
final override Instruction getAnyDef() { result = defInstr }
227278

228279
final override Overlap getDefinitionOverlap() {
229280
// All register results overlap exactly with their uses.
230281
result instanceof MustExactlyOverlap
231282
}
232283
}
233284

234-
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand {
285+
class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase {
235286
override MemoryOperandTag tag;
236-
Overlap overlap;
237287

238-
NonPhiMemoryOperand() { this = TNonPhiMemoryOperand(useInstr, tag, defInstr, overlap) }
288+
NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) }
239289

240-
final override Overlap getDefinitionOverlap() { result = overlap }
290+
final override string toString() { result = tag.toString() }
291+
292+
final override Instruction getAnyDef() {
293+
result = unique(Instruction defInstr | hasDefinition(defInstr, _))
294+
}
295+
296+
final override Overlap getDefinitionOverlap() { hasDefinition(_, result) }
297+
298+
pragma[noinline]
299+
private predicate hasDefinition(Instruction defInstr, Overlap overlap) {
300+
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
301+
not Construction::isInCycle(useInstr) and
302+
strictcount(Construction::getMemoryOperandDefinition(useInstr, tag, _)) = 1
303+
}
241304
}
242305

243306
class TypedOperand extends NonPhiMemoryOperand {
@@ -254,8 +317,6 @@ class TypedOperand extends NonPhiMemoryOperand {
254317
*/
255318
class AddressOperand extends RegisterOperand {
256319
override AddressOperandTag tag;
257-
258-
override string toString() { result = "Address" }
259320
}
260321

261322
/**
@@ -264,8 +325,6 @@ class AddressOperand extends RegisterOperand {
264325
*/
265326
class BufferSizeOperand extends RegisterOperand {
266327
override BufferSizeOperandTag tag;
267-
268-
override string toString() { result = "BufferSize" }
269328
}
270329

271330
/**
@@ -274,62 +333,48 @@ class BufferSizeOperand extends RegisterOperand {
274333
*/
275334
class LoadOperand extends TypedOperand {
276335
override LoadOperandTag tag;
277-
278-
override string toString() { result = "Load" }
279336
}
280337

281338
/**
282339
* The source value operand of a `Store` instruction.
283340
*/
284341
class StoreValueOperand extends RegisterOperand {
285342
override StoreValueOperandTag tag;
286-
287-
override string toString() { result = "StoreValue" }
288343
}
289344

290345
/**
291346
* The sole operand of a unary instruction (e.g. `Convert`, `Negate`, `Copy`).
292347
*/
293348
class UnaryOperand extends RegisterOperand {
294349
override UnaryOperandTag tag;
295-
296-
override string toString() { result = "Unary" }
297350
}
298351

299352
/**
300353
* The left operand of a binary instruction (e.g. `Add`, `CompareEQ`).
301354
*/
302355
class LeftOperand extends RegisterOperand {
303356
override LeftOperandTag tag;
304-
305-
override string toString() { result = "Left" }
306357
}
307358

308359
/**
309360
* The right operand of a binary instruction (e.g. `Add`, `CompareEQ`).
310361
*/
311362
class RightOperand extends RegisterOperand {
312363
override RightOperandTag tag;
313-
314-
override string toString() { result = "Right" }
315364
}
316365

317366
/**
318367
* The condition operand of a `ConditionalBranch` or `Switch` instruction.
319368
*/
320369
class ConditionOperand extends RegisterOperand {
321370
override ConditionOperandTag tag;
322-
323-
override string toString() { result = "Condition" }
324371
}
325372

326373
/**
327374
* The operand representing the target function of an `Call` instruction.
328375
*/
329376
class CallTargetOperand extends RegisterOperand {
330377
override CallTargetOperandTag tag;
331-
332-
override string toString() { result = "CallTarget" }
333378
}
334379

335380
/**
@@ -347,43 +392,34 @@ class ArgumentOperand extends RegisterOperand {
347392
*/
348393
class ThisArgumentOperand extends ArgumentOperand {
349394
override ThisArgumentOperandTag tag;
350-
351-
override string toString() { result = "ThisArgument" }
352395
}
353396

354397
/**
355398
* An operand representing an argument to a function call.
356399
*/
357400
class PositionalArgumentOperand extends ArgumentOperand {
358401
override PositionalArgumentOperandTag tag;
359-
int argIndex;
360-
361-
PositionalArgumentOperand() { argIndex = tag.getArgIndex() }
362-
363-
override string toString() { result = "Arg(" + argIndex + ")" }
364402

365403
/**
366404
* Gets the zero-based index of the argument.
367405
*/
368-
final int getIndex() { result = argIndex }
406+
final int getIndex() { result = tag.getArgIndex() }
369407
}
370408

371409
class SideEffectOperand extends TypedOperand {
372410
override SideEffectOperandTag tag;
373-
374-
override string toString() { result = "SideEffect" }
375411
}
376412

377413
/**
378414
* An operand of a `PhiInstruction`.
379415
*/
380-
class PhiInputOperand extends MemoryOperand, TPhiOperand {
416+
class PhiInputOperand extends MemoryOperand, PhiOperandBase {
381417
PhiInstruction useInstr;
382418
Instruction defInstr;
383419
IRBlock predecessorBlock;
384420
Overlap overlap;
385421

386-
PhiInputOperand() { this = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) }
422+
PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) }
387423

388424
override string toString() { result = "Phi" }
389425

@@ -413,8 +449,6 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand {
413449
class ChiTotalOperand extends NonPhiMemoryOperand {
414450
override ChiTotalOperandTag tag;
415451

416-
override string toString() { result = "ChiTotal" }
417-
418452
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiTotalMemoryAccess }
419453
}
420454

@@ -424,7 +458,5 @@ class ChiTotalOperand extends NonPhiMemoryOperand {
424458
class ChiPartialOperand extends NonPhiMemoryOperand {
425459
override ChiPartialOperandTag tag;
426460

427-
override string toString() { result = "ChiPartial" }
428-
429461
final override MemoryAccessKind getMemoryAccess() { result instanceof ChiPartialMemoryAccess }
430462
}

cpp/ql/src/semmle/code/cpp/ir/implementation/internal/OperandTag.qll

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,9 @@ PositionalArgumentOperandTag positionalArgumentOperand(int argIndex) {
221221
result = TPositionalArgumentOperand(argIndex)
222222
}
223223

224-
class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
224+
abstract class ChiOperandTag extends MemoryOperandTag { }
225+
226+
class ChiTotalOperandTag extends ChiOperandTag, TChiTotalOperand {
225227
final override string toString() { result = "ChiTotal" }
226228

227229
final override int getSortOrder() { result = 13 }
@@ -231,7 +233,7 @@ class ChiTotalOperandTag extends MemoryOperandTag, TChiTotalOperand {
231233

232234
ChiTotalOperandTag chiTotalOperand() { result = TChiTotalOperand() }
233235

234-
class ChiPartialOperandTag extends MemoryOperandTag, TChiPartialOperand {
236+
class ChiPartialOperandTag extends ChiOperandTag, TChiPartialOperand {
235237
final override string toString() { result = "ChiPartial" }
236238

237239
final override int getSortOrder() { result = 14 }

0 commit comments

Comments
 (0)