Skip to content

Commit 1b38208

Browse files
Merge pull request #1567 from jbj/ir-operand-cycles
C++ IR: guard against cycles in operand graph
2 parents c73b516 + 523fc9c commit 1b38208

File tree

3 files changed

+78
-6
lines changed

3 files changed

+78
-6
lines changed

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,39 @@ private import semmle.code.cpp.ir.internal.OperandTag
99
cached
1010
private newtype TOperand =
1111
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
12-
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag)
12+
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
13+
not isInCycle(useInstr)
1314
} or
1415
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
15-
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap)
16+
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
17+
not isInCycle(useInstr)
1618
} or
1719
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
1820
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
1921
}
2022

23+
/** Gets a non-phi instruction that defines an operand of `instr`. */
24+
private Instruction getNonPhiOperandDef(Instruction instr) {
25+
result = Construction::getRegisterOperandDefinition(instr, _)
26+
or
27+
result = Construction::getMemoryOperandDefinition(instr, _, _)
28+
}
29+
30+
/**
31+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
32+
* through a phi instruction and therefore should be impossible.
33+
*
34+
* If such cycles are present, either due to a programming error in the IR
35+
* generation or due to a malformed database, it can cause infinite loops in
36+
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
37+
* better to remove these operands than to leave cycles in the operand graph.
38+
*/
39+
pragma[noopt]
40+
private predicate isInCycle(Instruction instr) {
41+
instr instanceof Instruction and
42+
getNonPhiOperandDef+(instr) = instr
43+
}
44+
2145
/**
2246
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
2347
*/

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,39 @@ private import semmle.code.cpp.ir.internal.OperandTag
99
cached
1010
private newtype TOperand =
1111
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
12-
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag)
12+
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
13+
not isInCycle(useInstr)
1314
} or
1415
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
15-
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap)
16+
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
17+
not isInCycle(useInstr)
1618
} or
1719
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
1820
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
1921
}
2022

23+
/** Gets a non-phi instruction that defines an operand of `instr`. */
24+
private Instruction getNonPhiOperandDef(Instruction instr) {
25+
result = Construction::getRegisterOperandDefinition(instr, _)
26+
or
27+
result = Construction::getMemoryOperandDefinition(instr, _, _)
28+
}
29+
30+
/**
31+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
32+
* through a phi instruction and therefore should be impossible.
33+
*
34+
* If such cycles are present, either due to a programming error in the IR
35+
* generation or due to a malformed database, it can cause infinite loops in
36+
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
37+
* better to remove these operands than to leave cycles in the operand graph.
38+
*/
39+
pragma[noopt]
40+
private predicate isInCycle(Instruction instr) {
41+
instr instanceof Instruction and
42+
getNonPhiOperandDef+(instr) = instr
43+
}
44+
2145
/**
2246
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
2347
*/

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

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,39 @@ private import semmle.code.cpp.ir.internal.OperandTag
99
cached
1010
private newtype TOperand =
1111
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
12-
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag)
12+
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
13+
not isInCycle(useInstr)
1314
} or
1415
TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap) {
15-
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap)
16+
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
17+
not isInCycle(useInstr)
1618
} or
1719
TPhiOperand(PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap) {
1820
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
1921
}
2022

23+
/** Gets a non-phi instruction that defines an operand of `instr`. */
24+
private Instruction getNonPhiOperandDef(Instruction instr) {
25+
result = Construction::getRegisterOperandDefinition(instr, _)
26+
or
27+
result = Construction::getMemoryOperandDefinition(instr, _, _)
28+
}
29+
30+
/**
31+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
32+
* through a phi instruction and therefore should be impossible.
33+
*
34+
* If such cycles are present, either due to a programming error in the IR
35+
* generation or due to a malformed database, it can cause infinite loops in
36+
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
37+
* better to remove these operands than to leave cycles in the operand graph.
38+
*/
39+
pragma[noopt]
40+
private predicate isInCycle(Instruction instr) {
41+
instr instanceof Instruction and
42+
getNonPhiOperandDef+(instr) = instr
43+
}
44+
2145
/**
2246
* A source operand of an `Instruction`. The operand represents a value consumed by the instruction.
2347
*/

0 commit comments

Comments
 (0)