Skip to content

Commit 138a1c3

Browse files
committed
Fix calls for defer statements
1 parent 13bf978 commit 138a1c3

2 files changed

Lines changed: 14 additions & 1 deletion

File tree

go/ql/lib/semmle/go/controlflow/ControlFlowGraphShared.qll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,15 @@ module GoCfg {
354354
)
355355
}
356356

357-
predicate preOrderExpr(Ast::Expr e) { none() }
357+
predicate preOrderExpr(Ast::Expr e) {
358+
// The call of a `defer` statement is not invoked at the statement
359+
// itself; its callee and arguments are evaluated in place, but the call
360+
// is only invoked later, at function exit (modelled by the `defer-invoke`
361+
// node and `deferExitStep`). Marking it as pre-order means no in-order
362+
// "invocation" node (and hence no inline exceptional-exit edge) is
363+
// created at the `defer` statement.
364+
e = any(Go::DeferStmt s).getCall()
365+
}
358366

359367
predicate propagatesValue(Ast::AstNode child, Ast::AstNode parent) {
360368
child = parent.(Go::ParenExpr).getExpr()

go/ql/lib/semmle/go/controlflow/IR.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,11 @@ module IR {
218218
EvalInstruction() {
219219
this.isIn(e)
220220
or
221+
// The call of a `defer` statement is pre-order (it has no in-order
222+
// "invocation" node at the statement), so its value is produced by the
223+
// `defer-invoke` node that models the call at function exit.
224+
this.isAdditional(e, "defer-invoke")
225+
or
221226
// `NotExpr` and `LogicalBinaryExpr` are not in `postOrInOrder`, so they
222227
// don't have an `isIn` node. Only use the after-node when the
223228
// expression is not in a conditional context; otherwise the value is

0 commit comments

Comments
 (0)