From: Cherry Zhang Date: Mon, 29 Mar 2021 17:44:08 +0000 (-0400) Subject: cmd/compile: check deferred nil interface call before wrapping it X-Git-Tag: go1.17beta1~936 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=bd6628e62d;p=gostls13.git 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 --- 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.