Panic not recovered inside my panic recover function

143 views
Skip to first unread message

ZPL

unread,
Jul 17, 2019, 7:28:04 AM7/17/19
to golang-nuts
Hi, group. 

Recently I found an issue in our product, panic can't be recoved in some situation, I spend some time on it.  

Please find following simple Test function, I don't understand why logPanic function cant' catch the panic, but call recover directly can do that.


package main

import (
    "fmt"
    "sync"
    "testing"
)

var (
    groups = &sync.WaitGroup{}
)

func logPanic() {
    if err := recover(); err != nil {
        fmt.Println("got panic")
        return
    }
}

func DoTask() {
    DoTask1Panic()
    groups.Wait()
}

func DoTask1Panic() {
    groups.Add(1)

    go func() {
        defer func() {
// logPanic can't recover from panic here
            logPanic()
// But can recover from here
            // if err := recover(); err != nil {
            //  fmt.Println(err)
            // }
            groups.Done()
        }()
        panic("panic")
    }()
}

func TestPanic(t *testing.T) {
    DoTask()
    fmt.Println("Done")
}

Tamás Gulácsi

unread,
Jul 17, 2019, 8:11:40 AM7/17/19
to golang-nuts
The "recover()" call must be in the deferred part.

Ian Lance Taylor

unread,
Jul 17, 2019, 9:59:10 AM7/17/19
to Tamás Gulácsi, golang-nuts
On Wed, Jul 17, 2019 at 5:11 AM Tamás Gulácsi <tgula...@gmail.com> wrote:
>
> The "recover()" call must be in the deferred part.

Yes, as the spec says, recover must be called directly by a deferred function.

When sending code to this list, please use a link to the Go playground
or use plain text. The highlighted text with a black background is
unreadable. Thanks.

Ian

ZP L

unread,
Jul 18, 2019, 12:52:13 AM7/18/19
to Ian Lance Taylor, Tamás Gulácsi, golang-nuts
Sorry for the bad formatting.

> recover must be called directly by a deferred function
func logPanic() {
  defer func() {

     if err := recover(); err != nil {
       fmt.Println("got panic")
       return
      }
    }()
}
This still not working.



Recover is a built-in function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.

I think I didn't break any rules.


Ian Lance Taylor <ia...@golang.org> 于2019年7月17日周三 下午9:59写道:
--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/Ok40EBXxQ2Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golang-nuts...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAOyqgcXUWYdq%3DzSSw4V_HvNzrNpnrt1awEZbRFca0f6qHoBdsQ%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.


--
--刘志平

Ian Lance Taylor

unread,
Jul 18, 2019, 1:00:36 AM7/18/19
to ZP L, Tamás Gulácsi, golang-nuts
On Wed, Jul 17, 2019 at 9:51 PM ZP L <flyi...@gmail.com> wrote:
>
> Sorry for the bad formatting.
>
> > recover must be called directly by a deferred function
> func logPanic() {
> defer func() {
> if err := recover(); err != nil {
> fmt.Println("got panic")
> return
> }
> }()
> }
> This still not working.
>
>
>
> From https://blog.golang.org/defer-panic-and-recover,
>
> Recover is a built-in function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.
>
> I think I didn't break any rules.

If function F defers a function that calls recover, the recover
function will only catch a panic in the function F itself or in
functions that F calls. In the example above, the recover would catch
a panic in logPanic or in a function called by logPanic. But there is
no such panic, so recover always returns nil.

The reason that recover works this way is that a deferred function can
call another function that uses panic and recover. The different
calls to recover need to not interfere with each other.

Ian

Dan Kortschak

unread,
Jul 18, 2019, 1:03:42 AM7/18/19
to ZP L, golang-nuts
The defer is not being run directly as a result of the panic.

From the spec:

> The recover function allows a program to manage behavior of a
> panicking goroutine. Suppose a function G defers a function D that
> calls recover and a panic occurs in a function on the same goroutine
> in which G is executing. When the running of deferred functions
> reaches D, the return value of D's call to recover will be the value
> passed to the call of panic. If D returns normally, without starting
> a new panic, the panicking sequence stops.



On Thu, 2019-07-18 at 12:51 +0800, ZP L wrote:
> Sorry for the bad formatting.
>
> > recover must be called directly by a deferred function
>
> func logPanic() {
> defer func() {
> if err := recover(); err != nil {
> fmt.Println("got panic")
> return
> }
> }()
> }
> This still not working.
>
>
>
> From https://blog.golang.org/defer-panic-and-recover,
>
> *Recover* is a built-in function that regains control of a panicking
> goroutine. Recover is only useful inside deferred functions. During
> normal
> execution, a call to recover will return nil and have no other
> effect. *If
> the current goroutine is panicking, a call to recover will capture
> the
> value given to panic and resume normal execution.*

Dan Kortschak

unread,
Jul 18, 2019, 1:06:14 AM7/18/19
to ZP L, golang-nuts
You could try it this way if you really need a separate function.

https://play.golang.org/p/V-ysjWbZ2X5

On Thu, 2019-07-18 at 12:51 +0800, ZP L wrote:
> Sorry for the bad formatting.
>
> > recover must be called directly by a deferred function
>
> func logPanic() {
> defer func() {
> if err := recover(); err != nil {
> fmt.Println("got panic")
> return
> }
> }()
> }
> This still not working.
>
>
>
> From https://blog.golang.org/defer-panic-and-recover,
>
> *Recover* is a built-in function that regains control of a panicking
> goroutine. Recover is only useful inside deferred functions. During
> normal
> execution, a call to recover will return nil and have no other
> effect. *If
> the current goroutine is panicking, a call to recover will capture
> the
> value given to panic and resume normal execution.*

T L

unread,
Jul 18, 2019, 11:21:34 AM7/18/19
to golang-nuts


On Thursday, July 18, 2019 at 12:52:13 PM UTC+8, ZPL wrote:
Sorry for the bad formatting.

> recover must be called directly by a deferred function
func logPanic() {
  defer func() {
     if err := recover(); err != nil {
       fmt.Println("got panic")
       return
      }
    }()
}
This still not working.



Recover is a built-in function that regains control of a panicking goroutine. Recover is only useful inside deferred functions. During normal execution, a call to recover will return nil and have no other effect. If the current goroutine is panicking, a call to recover will capture the value given to panic and resume normal execution.

I think I didn't break any rules.


Ian Lance Taylor <ia...@golang.org> 于2019年7月17日周三 下午9:59写道:
On Wed, Jul 17, 2019 at 5:11 AM Tamás Gulácsi <tgula...@gmail.com> wrote:
>
> The "recover()" call must be in the deferred part.

Yes, as the spec says, recover must be called directly by a deferred function.

When sending code to this list, please use a link to the Go playground
or use plain text.  The highlighted text with a black background is
unreadable.  Thanks.

Ian

--
You received this message because you are subscribed to a topic in the Google Groups "golang-nuts" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/golang-nuts/Ok40EBXxQ2Q/unsubscribe.
To unsubscribe from this group and all its topics, send an email to golan...@googlegroups.com.


--
--刘志平
Reply all
Reply to author
Forward
0 new messages