Skip to content

Commit b44c458

Browse files
committed
CPP: Remove sucessors of non-returning IR calls.
1 parent e8dfecc commit b44c458

File tree

8 files changed

+417
-0
lines changed

8 files changed

+417
-0
lines changed

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
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

1574
pragma[noinline]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import semmle.code.cpp.ir.implementation.raw.IR as IR
22
import semmle.code.cpp.ir.implementation.raw.constant.ConstantAnalysis as ConstantAnalysis
3+
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/reachability/ReachableBlock.qll

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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)
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

1574
pragma[noinline]
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as IR
22
import semmle.code.cpp.ir.implementation.unaliased_ssa.constant.ConstantAnalysis as ConstantAnalysis
3+
import semmle.code.cpp.ir.internal.IRCppLanguage as Language

cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15740,6 +15740,112 @@ ir.cpp:
1574015740
# 2072| Value = [VariableAccess] 116
1574115741
# 2072| ValueCategory = prvalue(load)
1574215742
# 2073| getStmt(2): [ReturnStmt] return ...
15743+
# 2075| [TopLevelFunction] void exit(int)
15744+
# 2075| <params>:
15745+
# 2075| getParameter(0): [Parameter] code
15746+
# 2075| Type = [IntType] int
15747+
# 2077| [TopLevelFunction] int NonExit()
15748+
# 2077| <params>:
15749+
# 2077| getEntryPoint(): [BlockStmt] { ... }
15750+
# 2078| getStmt(0): [DeclStmt] declaration
15751+
# 2078| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
15752+
# 2078| Type = [IntType] int
15753+
# 2078| getVariable().getInitializer(): [Initializer] initializer for x
15754+
# 2078| getExpr(): [FunctionCall] call to Add
15755+
# 2078| Type = [IntType] int
15756+
# 2078| ValueCategory = prvalue
15757+
# 2078| getArgument(0): [Literal] 3
15758+
# 2078| Type = [IntType] int
15759+
# 2078| Value = [Literal] 3
15760+
# 2078| ValueCategory = prvalue
15761+
# 2078| getArgument(1): [Literal] 4
15762+
# 2078| Type = [IntType] int
15763+
# 2078| Value = [Literal] 4
15764+
# 2078| ValueCategory = prvalue
15765+
# 2079| getStmt(1): [IfStmt] if (...) ...
15766+
# 2079| getCondition(): [EQExpr] ... == ...
15767+
# 2079| Type = [BoolType] bool
15768+
# 2079| ValueCategory = prvalue
15769+
# 2079| getLeftOperand(): [VariableAccess] x
15770+
# 2079| Type = [IntType] int
15771+
# 2079| ValueCategory = prvalue(load)
15772+
# 2079| getRightOperand(): [Literal] 7
15773+
# 2079| Type = [IntType] int
15774+
# 2079| Value = [Literal] 7
15775+
# 2079| ValueCategory = prvalue
15776+
# 2080| getThen(): [ExprStmt] ExprStmt
15777+
# 2080| getExpr(): [FunctionCall] call to exit
15778+
# 2080| Type = [VoidType] void
15779+
# 2080| ValueCategory = prvalue
15780+
# 2080| getArgument(0): [Literal] 3
15781+
# 2080| Type = [IntType] int
15782+
# 2080| Value = [Literal] 3
15783+
# 2080| ValueCategory = prvalue
15784+
# 2081| getStmt(2): [ExprStmt] ExprStmt
15785+
# 2081| getExpr(): [FunctionCall] call to VoidFunc
15786+
# 2081| Type = [VoidType] void
15787+
# 2081| ValueCategory = prvalue
15788+
# 2082| getStmt(3): [ReturnStmt] return ...
15789+
# 2082| getExpr(): [VariableAccess] x
15790+
# 2082| Type = [IntType] int
15791+
# 2082| ValueCategory = prvalue(load)
15792+
# 2085| [TopLevelFunction] void CallsNonExit()
15793+
# 2085| <params>:
15794+
# 2085| getEntryPoint(): [BlockStmt] { ... }
15795+
# 2086| getStmt(0): [ExprStmt] ExprStmt
15796+
# 2086| getExpr(): [FunctionCall] call to VoidFunc
15797+
# 2086| Type = [VoidType] void
15798+
# 2086| ValueCategory = prvalue
15799+
# 2087| getStmt(1): [ExprStmt] ExprStmt
15800+
# 2087| getExpr(): [FunctionCall] call to exit
15801+
# 2087| Type = [VoidType] void
15802+
# 2087| ValueCategory = prvalue
15803+
# 2087| getArgument(0): [Literal] 3
15804+
# 2087| Type = [IntType] int
15805+
# 2087| Value = [Literal] 3
15806+
# 2087| ValueCategory = prvalue
15807+
# 2088| getStmt(2): [ReturnStmt] return ...
15808+
# 2090| [TopLevelFunction] int TransNonExit()
15809+
# 2090| <params>:
15810+
# 2090| getEntryPoint(): [BlockStmt] { ... }
15811+
# 2091| getStmt(0): [DeclStmt] declaration
15812+
# 2091| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
15813+
# 2091| Type = [IntType] int
15814+
# 2091| getVariable().getInitializer(): [Initializer] initializer for x
15815+
# 2091| getExpr(): [FunctionCall] call to Add
15816+
# 2091| Type = [IntType] int
15817+
# 2091| ValueCategory = prvalue
15818+
# 2091| getArgument(0): [Literal] 3
15819+
# 2091| Type = [IntType] int
15820+
# 2091| Value = [Literal] 3
15821+
# 2091| ValueCategory = prvalue
15822+
# 2091| getArgument(1): [Literal] 4
15823+
# 2091| Type = [IntType] int
15824+
# 2091| Value = [Literal] 4
15825+
# 2091| ValueCategory = prvalue
15826+
# 2092| getStmt(1): [IfStmt] if (...) ...
15827+
# 2092| getCondition(): [EQExpr] ... == ...
15828+
# 2092| Type = [BoolType] bool
15829+
# 2092| ValueCategory = prvalue
15830+
# 2092| getLeftOperand(): [VariableAccess] x
15831+
# 2092| Type = [IntType] int
15832+
# 2092| ValueCategory = prvalue(load)
15833+
# 2092| getRightOperand(): [Literal] 7
15834+
# 2092| Type = [IntType] int
15835+
# 2092| Value = [Literal] 7
15836+
# 2092| ValueCategory = prvalue
15837+
# 2093| getThen(): [ExprStmt] ExprStmt
15838+
# 2093| getExpr(): [FunctionCall] call to CallsNonExit
15839+
# 2093| Type = [VoidType] void
15840+
# 2093| ValueCategory = prvalue
15841+
# 2094| getStmt(2): [ExprStmt] ExprStmt
15842+
# 2094| getExpr(): [FunctionCall] call to VoidFunc
15843+
# 2094| Type = [VoidType] void
15844+
# 2094| ValueCategory = prvalue
15845+
# 2095| getStmt(3): [ReturnStmt] return ...
15846+
# 2095| getExpr(): [VariableAccess] x
15847+
# 2095| Type = [IntType] int
15848+
# 2095| ValueCategory = prvalue(load)
1574315849
perf-regression.cpp:
1574415850
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
1574515851
# 4| <params>:

cpp/ql/test/library-tests/ir/ir/ir.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2072,4 +2072,27 @@ void test_constant_folding() {
20722072
test_constant_folding_use(x);
20732073
}
20742074

2075+
void exit(int code);
2076+
2077+
int NonExit() {
2078+
int x = Add(3,4);
2079+
if (x == 7)
2080+
exit(3);
2081+
VoidFunc();
2082+
return x;
2083+
}
2084+
2085+
void CallsNonExit() {
2086+
VoidFunc();
2087+
exit(3);
2088+
}
2089+
2090+
int TransNonExit() {
2091+
int x = Add(3,4);
2092+
if (x == 7)
2093+
CallsNonExit();
2094+
VoidFunc();
2095+
return x;
2096+
}
2097+
20752098
// semmle-extractor-options: -std=c++17 --clang

cpp/ql/test/library-tests/ir/ir/operand_locations.expected

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9827,6 +9827,75 @@
98279827
| ir.cpp:2072:3:2072:27 | ChiTotal | total:m2070_4 |
98289828
| ir.cpp:2072:3:2072:27 | SideEffect | ~m2070_4 |
98299829
| ir.cpp:2072:29:2072:29 | Arg(0) | 0:r2072_2 |
9830+
| ir.cpp:2077:5:2077:11 | Address | &:r2077_6 |
9831+
| ir.cpp:2077:5:2077:11 | ChiPartial | partial:m2077_3 |
9832+
| ir.cpp:2077:5:2077:11 | ChiTotal | total:m2077_2 |
9833+
| ir.cpp:2077:5:2077:11 | Load | m2082_4 |
9834+
| ir.cpp:2077:5:2077:11 | SideEffect | ~m2081_4 |
9835+
| ir.cpp:2078:9:2078:9 | Address | &:r2078_1 |
9836+
| ir.cpp:2078:13:2078:15 | CallTarget | func:r2078_2 |
9837+
| ir.cpp:2078:13:2078:15 | ChiPartial | partial:m2078_6 |
9838+
| ir.cpp:2078:13:2078:15 | ChiTotal | total:m2077_4 |
9839+
| ir.cpp:2078:13:2078:15 | SideEffect | ~m2077_4 |
9840+
| ir.cpp:2078:13:2078:15 | StoreValue | r2078_5 |
9841+
| ir.cpp:2078:17:2078:17 | Arg(0) | 0:r2078_3 |
9842+
| ir.cpp:2078:19:2078:19 | Arg(1) | 1:r2078_4 |
9843+
| ir.cpp:2079:9:2079:9 | Address | &:r2079_1 |
9844+
| ir.cpp:2079:9:2079:9 | Left | r2079_2 |
9845+
| ir.cpp:2079:9:2079:9 | Load | m2078_8 |
9846+
| ir.cpp:2079:9:2079:14 | Condition | r2079_4 |
9847+
| ir.cpp:2079:14:2079:14 | Right | r2079_3 |
9848+
| ir.cpp:2080:9:2080:12 | CallTarget | func:r2080_1 |
9849+
| ir.cpp:2080:9:2080:12 | ChiPartial | partial:m2080_4 |
9850+
| ir.cpp:2080:9:2080:12 | ChiTotal | total:m2078_7 |
9851+
| ir.cpp:2080:9:2080:12 | SideEffect | ~m2078_7 |
9852+
| ir.cpp:2080:14:2080:14 | Arg(0) | 0:r2080_2 |
9853+
| ir.cpp:2081:5:2081:12 | CallTarget | func:r2081_1 |
9854+
| ir.cpp:2081:5:2081:12 | ChiPartial | partial:m2081_3 |
9855+
| ir.cpp:2081:5:2081:12 | ChiTotal | total:m2078_7 |
9856+
| ir.cpp:2081:5:2081:12 | SideEffect | ~m2078_7 |
9857+
| ir.cpp:2082:5:2082:13 | Address | &:r2082_1 |
9858+
| ir.cpp:2082:12:2082:12 | Address | &:r2082_2 |
9859+
| ir.cpp:2082:12:2082:12 | Load | m2078_8 |
9860+
| ir.cpp:2082:12:2082:12 | StoreValue | r2082_3 |
9861+
| ir.cpp:2085:6:2085:17 | ChiPartial | partial:m2085_3 |
9862+
| ir.cpp:2085:6:2085:17 | ChiTotal | total:m2085_2 |
9863+
| ir.cpp:2086:5:2086:12 | CallTarget | func:r2086_1 |
9864+
| ir.cpp:2086:5:2086:12 | ChiPartial | partial:m2086_3 |
9865+
| ir.cpp:2086:5:2086:12 | ChiTotal | total:m2085_4 |
9866+
| ir.cpp:2086:5:2086:12 | SideEffect | ~m2085_4 |
9867+
| ir.cpp:2087:5:2087:8 | CallTarget | func:r2087_1 |
9868+
| ir.cpp:2087:5:2087:8 | ChiPartial | partial:m2087_4 |
9869+
| ir.cpp:2087:5:2087:8 | ChiTotal | total:m2086_4 |
9870+
| ir.cpp:2087:5:2087:8 | SideEffect | ~m2086_4 |
9871+
| ir.cpp:2087:10:2087:10 | Arg(0) | 0:r2087_2 |
9872+
| ir.cpp:2090:5:2090:16 | Address | &:r2090_6 |
9873+
| ir.cpp:2090:5:2090:16 | ChiPartial | partial:m2090_3 |
9874+
| ir.cpp:2090:5:2090:16 | ChiTotal | total:m2090_2 |
9875+
| ir.cpp:2090:5:2090:16 | Load | m2095_4 |
9876+
| ir.cpp:2090:5:2090:16 | SideEffect | ~m2094_4 |
9877+
| ir.cpp:2091:9:2091:9 | Address | &:r2091_1 |
9878+
| ir.cpp:2091:13:2091:15 | CallTarget | func:r2091_2 |
9879+
| ir.cpp:2091:13:2091:15 | ChiPartial | partial:m2091_6 |
9880+
| ir.cpp:2091:13:2091:15 | ChiTotal | total:m2090_4 |
9881+
| ir.cpp:2091:13:2091:15 | SideEffect | ~m2090_4 |
9882+
| ir.cpp:2091:13:2091:15 | StoreValue | r2091_5 |
9883+
| ir.cpp:2091:17:2091:17 | Arg(0) | 0:r2091_3 |
9884+
| ir.cpp:2091:19:2091:19 | Arg(1) | 1:r2091_4 |
9885+
| ir.cpp:2092:9:2092:9 | Address | &:r2092_1 |
9886+
| ir.cpp:2092:9:2092:9 | Left | r2092_2 |
9887+
| ir.cpp:2092:9:2092:9 | Load | m2091_8 |
9888+
| ir.cpp:2092:9:2092:14 | Condition | r2092_4 |
9889+
| ir.cpp:2092:14:2092:14 | Right | r2092_3 |
9890+
| ir.cpp:2093:9:2093:20 | CallTarget | func:r2093_1 |
9891+
| ir.cpp:2094:5:2094:12 | CallTarget | func:r2094_1 |
9892+
| ir.cpp:2094:5:2094:12 | ChiPartial | partial:m2094_3 |
9893+
| ir.cpp:2094:5:2094:12 | ChiTotal | total:m2091_7 |
9894+
| ir.cpp:2094:5:2094:12 | SideEffect | ~m2091_7 |
9895+
| ir.cpp:2095:5:2095:13 | Address | &:r2095_1 |
9896+
| ir.cpp:2095:12:2095:12 | Address | &:r2095_2 |
9897+
| ir.cpp:2095:12:2095:12 | Load | m2091_8 |
9898+
| ir.cpp:2095:12:2095:12 | StoreValue | r2095_3 |
98309899
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
98319900
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
98329901
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

0 commit comments

Comments
 (0)