Skip to content

Commit 66876d0

Browse files
committed
C++: Compute isInCycle only for raw IR
On wireshark/wireshark, `isInCycle` ran into a low-memory loop on the `aliased_ssa` stage. It shouldn't be necessary to detect cycles after the `raw` stage, so this commit moves cycle detection into the `Construction` modules and makes it a no-op in `SSAConstruction.qll`.
1 parent 1c2f369 commit 66876d0

File tree

10 files changed

+86
-120
lines changed

10 files changed

+86
-120
lines changed

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,20 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr)
1515
} or
1616
TNonPhiMemoryOperand(
1717
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1818
) {
1919
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not isInCycle(useInstr)
20+
not Construction::isInCycle(useInstr)
2121
} or
2222
TPhiOperand(
2323
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
2424
) {
2525
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
2626
}
2727

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

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ private module Cached {
133133
overlap instanceof MustExactlyOverlap
134134
}
135135

136+
/**
137+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
138+
* through a phi instruction and therefore should be impossible.
139+
*
140+
* For performance reasons, this predicate is not implemented (never holds)
141+
* for the SSA stages of the IR.
142+
*/
143+
cached
144+
predicate isInCycle(Instruction instr) { none() }
145+
136146
cached
137147
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
138148
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,20 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr)
1515
} or
1616
TNonPhiMemoryOperand(
1717
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1818
) {
1919
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not isInCycle(useInstr)
20+
not Construction::isInCycle(useInstr)
2121
} or
2222
TPhiOperand(
2323
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
2424
) {
2525
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
2626
}
2727

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

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,29 @@ private module Cached {
9393
overlap instanceof MustTotallyOverlap
9494
}
9595

96+
/** Gets a non-phi instruction that defines an operand of `instr`. */
97+
private Instruction getNonPhiOperandDef(Instruction instr) {
98+
result = getRegisterOperandDefinition(instr, _)
99+
or
100+
result = getMemoryOperandDefinition(instr, _, _)
101+
}
102+
103+
/**
104+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
105+
* through a phi instruction and therefore should be impossible.
106+
*
107+
* If such cycles are present, either due to a programming error in the IR
108+
* generation or due to a malformed database, it can cause infinite loops in
109+
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
110+
* better to remove these operands than to leave cycles in the operand graph.
111+
*/
112+
pragma[noopt]
113+
cached
114+
predicate isInCycle(Instruction instr) {
115+
instr instanceof Instruction and
116+
getNonPhiOperandDef+(instr) = instr
117+
}
118+
96119
cached
97120
CppType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
98121
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,20 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr)
1515
} or
1616
TNonPhiMemoryOperand(
1717
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1818
) {
1919
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not isInCycle(useInstr)
20+
not Construction::isInCycle(useInstr)
2121
} or
2222
TPhiOperand(
2323
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
2424
) {
2525
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
2626
}
2727

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

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ private module Cached {
133133
overlap instanceof MustExactlyOverlap
134134
}
135135

136+
/**
137+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
138+
* through a phi instruction and therefore should be impossible.
139+
*
140+
* For performance reasons, this predicate is not implemented (never holds)
141+
* for the SSA stages of the IR.
142+
*/
143+
cached
144+
predicate isInCycle(Instruction instr) { none() }
145+
136146
cached
137147
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
138148
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,20 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr)
1515
} or
1616
TNonPhiMemoryOperand(
1717
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1818
) {
1919
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not isInCycle(useInstr)
20+
not Construction::isInCycle(useInstr)
2121
} or
2222
TPhiOperand(
2323
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
2424
) {
2525
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
2626
}
2727

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

csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,29 @@ private module Cached {
9595
.getInstructionOperand(getInstructionTag(instruction), tag)
9696
}
9797

98+
/** Gets a non-phi instruction that defines an operand of `instr`. */
99+
private Instruction getNonPhiOperandDef(Instruction instr) {
100+
result = getRegisterOperandDefinition(instr, _)
101+
or
102+
result = getMemoryOperandDefinition(instr, _, _)
103+
}
104+
105+
/**
106+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
107+
* through a phi instruction and therefore should be impossible.
108+
*
109+
* If such cycles are present, either due to a programming error in the IR
110+
* generation or due to a malformed database, it can cause infinite loops in
111+
* analyses that assume a cycle-free graph of non-phi operands. Therefore it's
112+
* better to remove these operands than to leave cycles in the operand graph.
113+
*/
114+
pragma[noopt]
115+
cached
116+
predicate isInCycle(Instruction instr) {
117+
instr instanceof Instruction and
118+
getNonPhiOperandDef+(instr) = instr
119+
}
120+
98121
cached
99122
CSharpType getInstructionOperandType(Instruction instruction, TypedOperandTag tag) {
100123
// For all `LoadInstruction`s, the operand type of the `LoadOperand` is the same as

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

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,20 @@ cached
1111
private newtype TOperand =
1212
TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) {
1313
defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and
14-
not isInCycle(useInstr)
14+
not Construction::isInCycle(useInstr)
1515
} or
1616
TNonPhiMemoryOperand(
1717
Instruction useInstr, MemoryOperandTag tag, Instruction defInstr, Overlap overlap
1818
) {
1919
defInstr = Construction::getMemoryOperandDefinition(useInstr, tag, overlap) and
20-
not isInCycle(useInstr)
20+
not Construction::isInCycle(useInstr)
2121
} or
2222
TPhiOperand(
2323
PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap
2424
) {
2525
defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap)
2626
}
2727

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

csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,16 @@ private module Cached {
133133
overlap instanceof MustExactlyOverlap
134134
}
135135

136+
/**
137+
* Holds if `instr` is part of a cycle in the operand graph that doesn't go
138+
* through a phi instruction and therefore should be impossible.
139+
*
140+
* For performance reasons, this predicate is not implemented (never holds)
141+
* for the SSA stages of the IR.
142+
*/
143+
cached
144+
predicate isInCycle(Instruction instr) { none() }
145+
136146
cached
137147
Language::LanguageType getInstructionOperandType(Instruction instr, TypedOperandTag tag) {
138148
exists(OldInstruction oldInstruction, OldIR::TypedOperand oldOperand |

0 commit comments

Comments
 (0)