Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6f2fd05

Browse files
authored
Merge pull request #354 from geoffw0/return-exception
CPP: Remove successor edges after calls to non-returning functions
2 parents b38effd + 9c97176 commit 6f2fd05

15 files changed

Lines changed: 622 additions & 435 deletions

File tree

cpp/ql/src/jsf/4.13 Functions/AV Rule 114.ql

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,17 @@ import cpp
1818
programmer, we can flag it anyway, since this is arguably a bug.) */
1919

2020
predicate functionsMissingReturnStmt(Function f, ControlFlowNode blame) {
21-
f.fromSource() and
22-
exists(Type returnType |
23-
returnType = f.getType().getUnderlyingType().getUnspecifiedType() and
24-
not returnType instanceof VoidType and
25-
not returnType instanceof TemplateParameter
26-
) and
27-
exists(ReturnStmt s | f.getAPredecessor() = s | blame = s.getAPredecessor())}
21+
f.fromSource() and
22+
exists(Type returnType |
23+
returnType = f.getType().getUnderlyingType().getUnspecifiedType() and
24+
not returnType instanceof VoidType and
25+
not returnType instanceof TemplateParameter
26+
) and
27+
exists(ReturnStmt s |
28+
f.getAPredecessor() = s and
29+
blame = s.getAPredecessor()
30+
)
31+
}
2832

2933
/* If a function has a value-carrying return statement, but the extractor hit a snag
3034
whilst parsing the value, then the control flow graph will not include the value.

cpp/ql/src/semmle/code/cpp/controlflow/BasicBlocks.qll

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -240,13 +240,18 @@ class BasicBlock extends ControlFlowNodeBase {
240240

241241
/**
242242
* Holds if control flow may reach this basic block from a function entry
243-
* point or a `catch` clause of a reachable `try` statement.
243+
* point or any handler of a reachable `try` statement.
244244
*/
245245
predicate isReachable() {
246246
exists(Function f | f.getBlock() = this)
247247
or
248-
exists(TryStmt t, BasicBlock tryblock | this = t.getACatchClause() and tryblock.isReachable() and tryblock.contains(t))
249-
or
248+
exists(TryStmt t, BasicBlock tryblock |
249+
// a `Handler` preceeds the `CatchBlock`, and is always the beginning
250+
// of a new `BasicBlock` (see `primitive_basic_block_entry_node`).
251+
this.(Handler).getTryStmt() = t and
252+
tryblock.isReachable() and
253+
tryblock.contains(t)
254+
) or
250255
exists(BasicBlock pred | pred.getASuccessor() = this and pred.isReachable())
251256
}
252257

cpp/ql/src/semmle/code/cpp/controlflow/ControlFlowGraph.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ private cached module Cached {
9595
or
9696
reachable(n.getAPredecessor())
9797
or
98-
n instanceof CatchBlock
98+
n instanceof Handler
9999
}
100100

101101
/** Holds if `condition` always evaluates to a nonzero value. */

cpp/ql/src/semmle/code/cpp/controlflow/internal/ConstantExprs.qll

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,28 @@ private predicate impossibleDefaultSwitchEdge(Block switchBlock, DefaultCase dc)
136136
val <= switchCaseRangeEnd(sc))))
137137
}
138138

139+
/**
140+
* Holds if the function `f` never returns due to not containing a return
141+
* statement (explicit or compiler generated). This can be thought of as
142+
* a lightweight `potentiallyReturningFunction`- reachability of return
143+
* statements is not checked.
144+
*/
145+
private predicate nonReturningFunction(Function f)
146+
{
147+
exists(f.getBlock()) and
148+
not exists(ReturnStmt ret | ret.getEnclosingFunction() = f) and
149+
not getOptions().exits(f)
150+
}
151+
152+
/**
153+
* An edge from a call to a function that never returns is impossible.
154+
*/
155+
private predicate impossibleFunctionReturn(FunctionCall fc, Node succ) {
156+
nonReturningFunction(fc.getTarget()) and
157+
not fc.isVirtual() and
158+
successors_extended(fc, succ)
159+
}
160+
139161
/**
140162
* If `pred` is a function call with (at least) one function target,
141163
* (at least) one such target must be potentially returning.
@@ -158,6 +180,7 @@ cached predicate successors_adapted(Node pred, Node succ) {
158180
and not impossibleTrueEdge(pred, succ)
159181
and not impossibleSwitchEdge(pred, succ)
160182
and not impossibleDefaultSwitchEdge(pred, succ)
183+
and not impossibleFunctionReturn(pred, succ)
161184
and not getOptions().exprExits(pred)
162185
}
163186

cpp/ql/src/semmle/code/cpp/controlflow/internal/PrimitiveBasicBlocks.qll

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,14 @@ private cached module Cached {
4444
// that the node have at least one successor.
4545
or
4646
(not successors_extended(_, node) and successors_extended(node, _))
47+
48+
// An exception handler is always the start of a new basic block. We
49+
// don't generate edges for [possible] exceptions, but in practice control
50+
// flow could reach the handler from anywhere inside the try block that
51+
// could throw an exception of a corresponding type. A `Handler` usually
52+
// needs to be considered reachable (see also `BasicBlock.isReachable`).
53+
or
54+
node instanceof Handler
4755
}
4856

4957
/** Holds if `n2` follows `n1` in a `PrimitiveBasicBlock`. */
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
| ODASA-5692.cpp:11:18:13:3 | { ... } |
22
| ODASA-5692.cpp:14:15:16:3 | { ... } |
33
| ODASA-5692.cpp:14:15:16:3 | { ... } |
4+
| exceptions.cpp:44:19:46:5 | { ... } |

cpp/ql/test/library-tests/c++_exceptions/catchparams.expected

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22
| exceptions.cpp:28:20:28:20 | e | exceptions.cpp:28:23:30:9 | { ... } |
33
| exceptions.cpp:32:16:32:16 | e | exceptions.cpp:32:19:34:5 | { ... } |
44
| exceptions.cpp:35:16:35:16 | e | exceptions.cpp:35:19:37:5 | { ... } |
5+
| exceptions.cpp:42:18:42:18 | e | exceptions.cpp:42:21:44:5 | { ... } |

cpp/ql/test/library-tests/c++_exceptions/exceptions.cpp

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,17 @@
22
void f1(void) throw (int);
33
void f2(void) throw ();
44
void f3(void);
5-
void f4(void) {
6-
return;
7-
}
8-
void f5(void) {
9-
throw 3;
10-
}
5+
void f4(void) { return; }
6+
void f5(void) { throw 3; }
117
void g(void);
128
void h(void);
139
void i(void);
1410
void j(void);
1511
void k(void);
12+
void l(void);
13+
void m(void);
14+
void n(void);
15+
1616

1717
void fun(void) {
1818
try {
@@ -36,5 +36,15 @@ void fun(void) {
3636
j();
3737
}
3838
k();
39+
40+
try {
41+
throw 7;
42+
} catch (int e) {
43+
l();
44+
} catch (...) {
45+
m();
46+
}
47+
n();
48+
3949
return;
4050
}

0 commit comments

Comments
 (0)