mirror of
https://github.com/github/codeql.git
synced 2026-05-02 20:25:13 +02:00
CPP: Remove sucessors of non-returning IR calls.
This commit is contained in:
@@ -10,6 +10,65 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
|
||||
or
|
||||
instr.getSuccessor(kind) instanceof UnreachedInstruction and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
isCallToNonReturningFunction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all calls to `f` never return (e.g. they call `exit` or loop forever)
|
||||
*/
|
||||
private predicate isNonReturningFunction(IRFunction f) {
|
||||
// If the function has an instruction with a missing successor then
|
||||
// the analysis is probably going to be incorrect, so assume they exit.
|
||||
not hasInstructionWithMissingSuccessor(f) and
|
||||
(
|
||||
// If all flows to the exit block are pass through an unreachable then f never returns.
|
||||
any(UnreachedInstruction instr).getBlock().postDominates(f.getEntryBlock())
|
||||
or
|
||||
// If there is no flow to the exit block then f never returns.
|
||||
not exists(IRBlock entry, IRBlock exit |
|
||||
exit = f.getExitFunctionInstruction().getBlock() and
|
||||
entry = f.getEntryBlock() and
|
||||
exit = entry.getASuccessor*()
|
||||
)
|
||||
or
|
||||
// If all flows to the exit block are pass through a call that never returns then f never returns.
|
||||
exists(CallInstruction ci |
|
||||
ci.getBlock().postDominates(f.getEntryBlock()) and
|
||||
isCallToNonReturningFunction(ci)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` has an instruction with a missing successor.
|
||||
* This matches `instructionWithoutSuccessor` from `IRConsistency`, but
|
||||
* avoids generating the error strings.
|
||||
*/
|
||||
predicate hasInstructionWithMissingSuccessor(IRFunction f) {
|
||||
exists(Instruction missingSucc |
|
||||
missingSucc.getEnclosingIRFunction() = f and
|
||||
not exists(missingSucc.getASuccessor()) and
|
||||
not missingSucc instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not missingSucc instanceof PhiInstruction and
|
||||
not missingSucc instanceof UnreachedInstruction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call `ci` never returns.
|
||||
*/
|
||||
private predicate isCallToNonReturningFunction(CallInstruction ci) {
|
||||
exists(IRFunction callee, Language::Function staticTarget |
|
||||
staticTarget = ci.getStaticCallTarget() and
|
||||
staticTarget = callee.getFunction() and
|
||||
// We can't easily tell if the call is virtual or not
|
||||
// if the callee is virtual. So assume that the call is virtual
|
||||
// if the target is.
|
||||
not staticTarget.isVirtual() and
|
||||
isNonReturningFunction(callee)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.raw.IR as IR
|
||||
import semmle.code.cpp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
|
||||
@@ -10,6 +10,65 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
|
||||
or
|
||||
instr.getSuccessor(kind) instanceof UnreachedInstruction and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
isCallToNonReturningFunction(instr)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all calls to `f` never return (e.g. they call `exit` or loop forever)
|
||||
*/
|
||||
private predicate isNonReturningFunction(IRFunction f) {
|
||||
// If the function has an instruction with a missing successor then
|
||||
// the analysis is probably going to be incorrect, so assume they exit.
|
||||
not hasInstructionWithMissingSuccessor(f) and
|
||||
(
|
||||
// If all flows to the exit block are pass through an unreachable then f never returns.
|
||||
any(UnreachedInstruction instr).getBlock().postDominates(f.getEntryBlock())
|
||||
or
|
||||
// If there is no flow to the exit block then f never returns.
|
||||
not exists(IRBlock entry, IRBlock exit |
|
||||
exit = f.getExitFunctionInstruction().getBlock() and
|
||||
entry = f.getEntryBlock() and
|
||||
exit = entry.getASuccessor*()
|
||||
)
|
||||
or
|
||||
// If all flows to the exit block are pass through a call that never returns then f never returns.
|
||||
exists(CallInstruction ci |
|
||||
ci.getBlock().postDominates(f.getEntryBlock()) and
|
||||
isCallToNonReturningFunction(ci)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `f` has an instruction with a missing successor.
|
||||
* This matches `instructionWithoutSuccessor` from `IRConsistency`, but
|
||||
* avoids generating the error strings.
|
||||
*/
|
||||
predicate hasInstructionWithMissingSuccessor(IRFunction f) {
|
||||
exists(Instruction missingSucc |
|
||||
missingSucc.getEnclosingIRFunction() = f and
|
||||
not exists(missingSucc.getASuccessor()) and
|
||||
not missingSucc instanceof ExitFunctionInstruction and
|
||||
// Phi instructions aren't linked into the instruction-level flow graph.
|
||||
not missingSucc instanceof PhiInstruction and
|
||||
not missingSucc instanceof UnreachedInstruction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the call `ci` never returns.
|
||||
*/
|
||||
private predicate isCallToNonReturningFunction(CallInstruction ci) {
|
||||
exists(IRFunction callee, Language::Function staticTarget |
|
||||
staticTarget = ci.getStaticCallTarget() and
|
||||
staticTarget = callee.getFunction() and
|
||||
// We can't easily tell if the call is virtual or not
|
||||
// if the callee is virtual. So assume that the call is virtual
|
||||
// if the target is.
|
||||
not staticTarget.isVirtual() and
|
||||
isNonReturningFunction(callee)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
|
||||
Reference in New Issue
Block a user