From b2e5d235de324ba1e3f5a041c2c2a7028812b460 Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Wed, 23 Jan 2019 11:07:49 +0100 Subject: [PATCH] C++: IR sanity queries for outgoing edges These queries have no results on our test cases in the repo, but `ambiguousSuccessors` has results on any large C++ code base, and `unexplainedLoop` has results on Windows builds of ChakraCore. --- .../aliased_ssa/Instruction.qll | 26 +++++++++++++++++++ .../cpp/ir/implementation/raw/Instruction.qll | 26 +++++++++++++++++++ .../unaliased_ssa/Instruction.qll | 26 +++++++++++++++++++ .../ir/ir/aliased_ssa_sanity.expected | 2 ++ .../library-tests/ir/ir/raw_sanity.expected | 2 ++ .../ir/ir/unaliased_ssa_sanity.expected | 2 ++ 6 files changed, 84 insertions(+) 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