diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index dcad960d8dfd..ad7df6a2159d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -106,6 +106,32 @@ module InstructionSanity { not instr instanceof UnreachedInstruction } + /** + * Holds if there are multiple (`n`) edges of kind `kind` from `source`, + * where `target` is among the targets of those edges. + */ + query predicate ambiguousSuccessors( + Instruction source, EdgeKind kind, int n, Instruction target + ) { + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + source.getSuccessor(kind) = target + } + + /** + * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * contains no element that can cause loops. + */ + query predicate unexplainedLoop(Function f, Instruction instr) { + exists(IRBlock block | + instr.getBlock() = block and + block.getFunction() = f and + block.getASuccessor+() = block + ) and + not exists(Loop l | l.getEnclosingFunction() = f) and + not exists(GotoStmt s | s.getEnclosingFunction() = f) + } + /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index dcad960d8dfd..ad7df6a2159d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -106,6 +106,32 @@ module InstructionSanity { not instr instanceof UnreachedInstruction } + /** + * Holds if there are multiple (`n`) edges of kind `kind` from `source`, + * where `target` is among the targets of those edges. + */ + query predicate ambiguousSuccessors( + Instruction source, EdgeKind kind, int n, Instruction target + ) { + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + source.getSuccessor(kind) = target + } + + /** + * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * contains no element that can cause loops. + */ + query predicate unexplainedLoop(Function f, Instruction instr) { + exists(IRBlock block | + instr.getBlock() = block and + block.getFunction() = f and + block.getASuccessor+() = block + ) and + not exists(Loop l | l.getEnclosingFunction() = f) and + not exists(GotoStmt s | s.getEnclosingFunction() = f) + } + /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index dcad960d8dfd..ad7df6a2159d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -106,6 +106,32 @@ module InstructionSanity { not instr instanceof UnreachedInstruction } + /** + * Holds if there are multiple (`n`) edges of kind `kind` from `source`, + * where `target` is among the targets of those edges. + */ + query predicate ambiguousSuccessors( + Instruction source, EdgeKind kind, int n, Instruction target + ) { + n = strictcount(Instruction t | source.getSuccessor(kind) = t) and + n > 1 and + source.getSuccessor(kind) = target + } + + /** + * Holds if `instr` in `f` is part of a loop even though the AST of `f` + * contains no element that can cause loops. + */ + query predicate unexplainedLoop(Function f, Instruction instr) { + exists(IRBlock block | + instr.getBlock() = block and + block.getFunction() = f and + block.getASuccessor+() = block + ) and + not exists(Loop l | l.getEnclosingFunction() = f) and + not exists(GotoStmt s | s.getEnclosingFunction() = f) + } + /** * Holds if a `Phi` instruction is present in a block with fewer than two * predecessors. diff --git a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected index 95989fc88090..4513d33fbd9e 100644 --- a/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/aliased_ssa_sanity.expected @@ -3,6 +3,8 @@ unexpectedOperand duplicateOperand missingPhiOperand instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop unnecessaryPhiInstruction operandAcrossFunctions instructionWithoutUniqueBlock diff --git a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected index 95989fc88090..4513d33fbd9e 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_sanity.expected @@ -3,6 +3,8 @@ unexpectedOperand duplicateOperand missingPhiOperand instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop unnecessaryPhiInstruction operandAcrossFunctions instructionWithoutUniqueBlock diff --git a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected index 95989fc88090..4513d33fbd9e 100644 --- a/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected +++ b/cpp/ql/test/library-tests/ir/ir/unaliased_ssa_sanity.expected @@ -3,6 +3,8 @@ unexpectedOperand duplicateOperand missingPhiOperand instructionWithoutSuccessor +ambiguousSuccessors +unexplainedLoop unnecessaryPhiInstruction operandAcrossFunctions instructionWithoutUniqueBlock