Skip to content

Commit b3bb71f

Browse files
committed
Java: Update the CFG for assert statements to make them proper guards.
1 parent 31770ed commit b3bb71f

File tree

1 file changed

+38
-11
lines changed

1 file changed

+38
-11
lines changed

java/ql/lib/semmle/code/java/ControlFlowGraph.qll

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -327,12 +327,18 @@ private module ControlFlowGraphImpl {
327327
)
328328
}
329329

330+
private ThrowableType assertionError() { result.hasQualifiedName("java.lang", "AssertionError") }
331+
330332
/**
331333
* Gets an exception type that may be thrown during execution of the
332334
* body or the resources (if any) of `try`.
333335
*/
334336
private ThrowableType thrownInBody(TryStmt try) {
335-
exists(AstNode n | mayThrow(n, result) |
337+
exists(AstNode n |
338+
mayThrow(n, result)
339+
or
340+
n instanceof AssertStmt and result = assertionError()
341+
|
336342
n.getEnclosingStmt().getEnclosingStmt+() = try.getBlock() or
337343
n.(Expr).getParent*() = try.getAResource()
338344
)
@@ -394,10 +400,7 @@ private module ControlFlowGraphImpl {
394400
exists(LogicExpr logexpr |
395401
logexpr.(BinaryExpr).getLeftOperand() = b
396402
or
397-
// Cannot use LogicExpr.getAnOperand or BinaryExpr.getAnOperand as they remove parentheses.
398-
logexpr.(BinaryExpr).getRightOperand() = b and inBooleanContext(logexpr)
399-
or
400-
logexpr.(UnaryExpr).getExpr() = b and inBooleanContext(logexpr)
403+
logexpr.getAnOperand() = b and inBooleanContext(logexpr)
401404
)
402405
or
403406
exists(ConditionalExpr condexpr |
@@ -407,6 +410,8 @@ private module ControlFlowGraphImpl {
407410
inBooleanContext(condexpr)
408411
)
409412
or
413+
exists(AssertStmt assertstmt | assertstmt.getExpr() = b)
414+
or
410415
exists(SwitchExpr switch |
411416
inBooleanContext(switch) and
412417
switch.getAResult() = b
@@ -672,8 +677,6 @@ private module ControlFlowGraphImpl {
672677
this instanceof EmptyStmt
673678
or
674679
this instanceof LocalTypeDeclStmt
675-
or
676-
this instanceof AssertStmt
677680
}
678681

679682
/** Gets child nodes in their order of execution. Indexing starts at either -1 or 0. */
@@ -744,8 +747,6 @@ private module ControlFlowGraphImpl {
744747
or
745748
index = 0 and result = this.(ThrowStmt).getExpr()
746749
or
747-
index = 0 and result = this.(AssertStmt).getExpr()
748-
or
749750
result = this.(RecordPatternExpr).getSubPattern(index)
750751
}
751752

@@ -807,9 +808,12 @@ private module ControlFlowGraphImpl {
807808
or
808809
result = first(n.(SynchronizedStmt).getExpr())
809810
or
811+
result = first(n.(AssertStmt).getExpr())
812+
or
810813
result.asStmt() = n and
811814
not n instanceof PostOrderNode and
812-
not n instanceof SynchronizedStmt
815+
not n instanceof SynchronizedStmt and
816+
not n instanceof AssertStmt
813817
or
814818
result.asExpr() = n and n instanceof SwitchExpr
815819
}
@@ -1112,7 +1116,19 @@ private module ControlFlowGraphImpl {
11121116
// `return` statements give rise to a `Return` completion
11131117
last.asStmt() = n.(ReturnStmt) and completion = ReturnCompletion()
11141118
or
1115-
// `throw` statements or throwing calls give rise to ` Throw` completion
1119+
exists(AssertStmt assertstmt | assertstmt = n |
1120+
// `assert` statements may complete normally - we use the `AssertStmt` itself
1121+
// to represent this outcome
1122+
last.asStmt() = assertstmt and completion = NormalCompletion()
1123+
or
1124+
// `assert` statements may throw
1125+
completion = ThrowCompletion(assertionError()) and
1126+
if exists(assertstmt.getMessage())
1127+
then last(assertstmt.getMessage(), last, NormalCompletion())
1128+
else last(assertstmt.getExpr(), last, BooleanCompletion(false, _))
1129+
)
1130+
or
1131+
// `throw` statements or throwing calls give rise to `Throw` completion
11161132
exists(ThrowableType tt | mayThrow(n, tt) |
11171133
last = n.getCfgNode() and completion = ThrowCompletion(tt)
11181134
)
@@ -1520,6 +1536,17 @@ private module ControlFlowGraphImpl {
15201536
exists(int i | last(s.getVariable(i), n, completion) and result = first(s.getVariable(i + 1)))
15211537
)
15221538
or
1539+
// Assert statements:
1540+
exists(AssertStmt assertstmt |
1541+
last(assertstmt.getExpr(), n, completion) and
1542+
completion = BooleanCompletion(true, _) and
1543+
result.asStmt() = assertstmt
1544+
or
1545+
last(assertstmt.getExpr(), n, completion) and
1546+
completion = BooleanCompletion(false, _) and
1547+
result = first(assertstmt.getMessage())
1548+
)
1549+
or
15231550
// When expressions:
15241551
exists(WhenExpr whenexpr |
15251552
n.asExpr() = whenexpr and

0 commit comments

Comments
 (0)