@@ -10,6 +10,65 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
1010 or
1111 instr .getSuccessor ( kind ) instanceof UnreachedInstruction and
1212 kind instanceof GotoEdge
13+ or
14+ isCallToNonReturningFunction ( instr ) and exists ( instr .getSuccessor ( kind ) )
15+ }
16+
17+ /**
18+ * Holds if all calls to `f` never return (e.g. they call `exit` or loop forever)
19+ */
20+ private predicate isNonReturningFunction ( IRFunction f ) {
21+ // If the function has an instruction with a missing successor then
22+ // the analysis is probably going to be incorrect, so assume they exit.
23+ not hasInstructionWithMissingSuccessor ( f ) and
24+ (
25+ // If all flows to the exit block are pass through an unreachable then f never returns.
26+ any ( UnreachedInstruction instr ) .getBlock ( ) .postDominates ( f .getEntryBlock ( ) )
27+ or
28+ // If there is no flow to the exit block then f never returns.
29+ not exists ( IRBlock entry , IRBlock exit |
30+ exit = f .getExitFunctionInstruction ( ) .getBlock ( ) and
31+ entry = f .getEntryBlock ( ) and
32+ exit = entry .getASuccessor * ( )
33+ )
34+ or
35+ // If all flows to the exit block are pass through a call that never returns then f never returns.
36+ exists ( CallInstruction ci |
37+ ci .getBlock ( ) .postDominates ( f .getEntryBlock ( ) ) and
38+ isCallToNonReturningFunction ( ci )
39+ )
40+ )
41+ }
42+
43+ /**
44+ * Holds if `f` has an instruction with a missing successor.
45+ * This matches `instructionWithoutSuccessor` from `IRConsistency`, but
46+ * avoids generating the error strings.
47+ */
48+ predicate hasInstructionWithMissingSuccessor ( IRFunction f ) {
49+ exists ( Instruction missingSucc |
50+ missingSucc .getEnclosingIRFunction ( ) = f and
51+ not exists ( missingSucc .getASuccessor ( ) ) and
52+ not missingSucc instanceof ExitFunctionInstruction and
53+ // Phi instructions aren't linked into the instruction-level flow graph.
54+ not missingSucc instanceof PhiInstruction and
55+ not missingSucc instanceof UnreachedInstruction
56+ )
57+ }
58+
59+ /**
60+ * Holds if the call `ci` never returns.
61+ */
62+ private predicate isCallToNonReturningFunction ( CallInstruction ci ) {
63+ exists ( IRFunction callee , Language:: Function staticTarget |
64+ staticTarget = ci .getStaticCallTarget ( ) and
65+ staticTarget = callee .getFunction ( ) and
66+ // We can't easily tell if the call is virtual or not
67+ // if the callee is virtual. So assume that the call is virtual
68+ // if the target is.
69+ not staticTarget .isVirtual ( ) and
70+ isNonReturningFunction ( callee )
71+ )
1372}
1473
1574pragma [ noinline]
0 commit comments