Skip to content

Commit 62509ff

Browse files
committed
C++: Add a back-edge safeguard
This prevents loops of non-back-edges on ChakraCore (see #811).
1 parent 5b2b961 commit 62509ff

File tree

6 files changed

+114
-9
lines changed

6 files changed

+114
-9
lines changed

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private predicate startsBasicBlock(Instruction instr) {
138138
not kind instanceof GotoEdge
139139
) or // Incoming edge is not a GotoEdge
140140
exists(Instruction predecessor |
141-
instr = predecessor.getBackEdgeSuccessor(_)
141+
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
142142
) // A back edge enters this instruction
143143
)
144144
}
@@ -192,9 +192,36 @@ private cached module Cached {
192192
}
193193

194194
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
backEdgeSuccessorRaw(pred, succ, kind)
196+
or
197+
forwardEdgeRaw+(pred, pred) and
198+
blockSuccessor(pred, succ, kind)
199+
}
200+
201+
/**
202+
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
203+
*/
204+
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
205+
exists(EdgeKind kind |
206+
blockSuccessor(pred, succ, kind) and
207+
not backEdgeSuccessorRaw(pred, succ, kind)
208+
)
209+
}
210+
211+
/**
212+
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
213+
* `Construction`.
214+
*
215+
* There could be loops of non-back-edges if there is a flaw in the IR
216+
* construction or back-edge detection, and this could cause non-termination
217+
* of subsequent analysis. To prevent that, a subsequent predicate further
218+
* classifies all edges as back edges if they are involved in a loop of
219+
* non-back-edges.
220+
*/
221+
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195222
exists(Instruction predLast, Instruction succFirst |
196223
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197-
succFirst = predLast.getBackEdgeSuccessor(kind) and
224+
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
198225
succ = MkIRBlock(succFirst)
199226
)
200227
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,15 @@ class Instruction extends Construction::TInstruction {
518518
* removed from the control-flow graph, it becomes acyclic.
519519
*/
520520
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
521-
result = Construction::getInstructionBackEdgeSuccessor(this, kind)
521+
// We don't take these edges from
522+
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
523+
// not been treated to remove any loops that might be left over due to
524+
// flaws in the IR construction or back-edge detection.
525+
exists(IRBlock block |
526+
block = this.getBlock() and
527+
this = block.getLastInstruction() and
528+
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
529+
)
522530
}
523531

524532
/**

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private predicate startsBasicBlock(Instruction instr) {
138138
not kind instanceof GotoEdge
139139
) or // Incoming edge is not a GotoEdge
140140
exists(Instruction predecessor |
141-
instr = predecessor.getBackEdgeSuccessor(_)
141+
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
142142
) // A back edge enters this instruction
143143
)
144144
}
@@ -192,9 +192,36 @@ private cached module Cached {
192192
}
193193

194194
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
backEdgeSuccessorRaw(pred, succ, kind)
196+
or
197+
forwardEdgeRaw+(pred, pred) and
198+
blockSuccessor(pred, succ, kind)
199+
}
200+
201+
/**
202+
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
203+
*/
204+
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
205+
exists(EdgeKind kind |
206+
blockSuccessor(pred, succ, kind) and
207+
not backEdgeSuccessorRaw(pred, succ, kind)
208+
)
209+
}
210+
211+
/**
212+
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
213+
* `Construction`.
214+
*
215+
* There could be loops of non-back-edges if there is a flaw in the IR
216+
* construction or back-edge detection, and this could cause non-termination
217+
* of subsequent analysis. To prevent that, a subsequent predicate further
218+
* classifies all edges as back edges if they are involved in a loop of
219+
* non-back-edges.
220+
*/
221+
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195222
exists(Instruction predLast, Instruction succFirst |
196223
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197-
succFirst = predLast.getBackEdgeSuccessor(kind) and
224+
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
198225
succ = MkIRBlock(succFirst)
199226
)
200227
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,15 @@ class Instruction extends Construction::TInstruction {
518518
* removed from the control-flow graph, it becomes acyclic.
519519
*/
520520
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
521-
result = Construction::getInstructionBackEdgeSuccessor(this, kind)
521+
// We don't take these edges from
522+
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
523+
// not been treated to remove any loops that might be left over due to
524+
// flaws in the IR construction or back-edge detection.
525+
exists(IRBlock block |
526+
block = this.getBlock() and
527+
this = block.getLastInstruction() and
528+
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
529+
)
522530
}
523531

524532
/**

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ private predicate startsBasicBlock(Instruction instr) {
138138
not kind instanceof GotoEdge
139139
) or // Incoming edge is not a GotoEdge
140140
exists(Instruction predecessor |
141-
instr = predecessor.getBackEdgeSuccessor(_)
141+
instr = Construction::getInstructionBackEdgeSuccessor(predecessor, _)
142142
) // A back edge enters this instruction
143143
)
144144
}
@@ -192,9 +192,36 @@ private cached module Cached {
192192
}
193193

194194
cached predicate backEdgeSuccessor(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195+
backEdgeSuccessorRaw(pred, succ, kind)
196+
or
197+
forwardEdgeRaw+(pred, pred) and
198+
blockSuccessor(pred, succ, kind)
199+
}
200+
201+
/**
202+
* Holds if there is an edge from `pred` to `succ` that is not a back edge.
203+
*/
204+
private predicate forwardEdgeRaw(TIRBlock pred, TIRBlock succ) {
205+
exists(EdgeKind kind |
206+
blockSuccessor(pred, succ, kind) and
207+
not backEdgeSuccessorRaw(pred, succ, kind)
208+
)
209+
}
210+
211+
/**
212+
* Holds if the `kind`-edge from `pred` to `succ` is a back edge according to
213+
* `Construction`.
214+
*
215+
* There could be loops of non-back-edges if there is a flaw in the IR
216+
* construction or back-edge detection, and this could cause non-termination
217+
* of subsequent analysis. To prevent that, a subsequent predicate further
218+
* classifies all edges as back edges if they are involved in a loop of
219+
* non-back-edges.
220+
*/
221+
private predicate backEdgeSuccessorRaw(TIRBlock pred, TIRBlock succ, EdgeKind kind) {
195222
exists(Instruction predLast, Instruction succFirst |
196223
predLast = getInstruction(pred, getInstructionCount(pred) - 1) and
197-
succFirst = predLast.getBackEdgeSuccessor(kind) and
224+
succFirst = Construction::getInstructionBackEdgeSuccessor(predLast, kind) and
198225
succ = MkIRBlock(succFirst)
199226
)
200227
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,15 @@ class Instruction extends Construction::TInstruction {
518518
* removed from the control-flow graph, it becomes acyclic.
519519
*/
520520
final Instruction getBackEdgeSuccessor(EdgeKind kind) {
521-
result = Construction::getInstructionBackEdgeSuccessor(this, kind)
521+
// We don't take these edges from
522+
// `Construction::getInstructionBackEdgeSuccessor` since that relation has
523+
// not been treated to remove any loops that might be left over due to
524+
// flaws in the IR construction or back-edge detection.
525+
exists(IRBlock block |
526+
block = this.getBlock() and
527+
this = block.getLastInstruction() and
528+
result = block.getBackEdgeSuccessor(kind).getFirstInstruction()
529+
)
522530
}
523531

524532
/**

0 commit comments

Comments
 (0)