From bd6628e62dd5ef1e389d6551a83ef4f2baabebb5 Mon Sep 17 00:00:00 2001 From: Cherry Zhang Date: Mon, 29 Mar 2021 13:44:08 -0400 Subject: [PATCH] cmd/compile: check deferred nil interface call before wrapping it Currently, for "defer i.M()" if i is nil it panics at the point of defer statement, not when deferred function is called. We need to do the nil check before wrapping it. Updates #40724. Change-Id: I62c669264668991f71999e2cf4610a9066247f9d Reviewed-on: https://go-review.googlesource.com/c/go/+/305549 Trust: Cherry Zhang Reviewed-by: David Chase Reviewed-by: Than McIntosh --- src/cmd/compile/internal/walk/order.go | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/cmd/compile/internal/walk/order.go b/src/cmd/compile/internal/walk/order.go index 95d245d0d7..9e6c58054d 100644 --- a/src/cmd/compile/internal/walk/order.go +++ b/src/cmd/compile/internal/walk/order.go @@ -1602,6 +1602,17 @@ func (o *orderState) wrapGoDefer(n *ir.GoDeferStmt) { n := callX.(*ir.SelectorExpr) n.X = mkArgCopy(n.X) methSelectorExpr = n + if callX.Op() == ir.ODOTINTER { + // Currently for "defer i.M()" if i is nil it panics at the + // point of defer statement, not when deferred function is called. + // (I think there is an issue discussing what is the intended + // behavior but I cannot find it.) + // We need to do the nil check outside of the wrapper. + tab := typecheck.Expr(ir.NewUnaryExpr(base.Pos, ir.OITAB, n.X)) + c := ir.NewUnaryExpr(n.Pos(), ir.OCHECKNIL, tab) + c.SetTypecheck(1) + o.append(c) + } case !(callX.Op() == ir.ONAME && callX.(*ir.Name).Class == ir.PFUNC): // Deal with "defer returnsafunc()(x, y)" (for // example) by copying the callee expression.