无法从恐慌中恢复过来 - defer 被完全跳过

Can't recover from panic - defer is entirely skipped

当对无效的编写器使用 io.Copy 时,我会感到恐慌 - 这是预料之中的。但是,在这种情况下我无法恢复。我的延迟恢复被完全绕过了。这是代码:

package main

import (
    "context"
    "fmt"
    "io"
    "log"
    "os"
    "runtime"
    "runtime/debug"

    "cloud.google.com/go/storage"
)

func main() {
    var (
        ctx      = context.Background()
        fromFile = "blah.txt"
        bucket   = "blah-bucket"
        path     = "blah-path"
    )

    defer func() {
        if result := recover(); result != nil {
            buf := make([]byte, 1<<16)
            length := runtime.Stack(buf, false)
            log.Fatalf("PANIC RECOVER: %v\nSTACK: \n%s", result, buf[:length])
            debug.PrintStack()
        }
    }()

    err := FakeUpload(ctx, fromFile, bucket, path)
    if err != nil {
        fmt.Println(err)
    }

    fmt.Println("HELLO")
}

func FakeUpload(ctx context.Context, fromFile, toBucket, toPath string) (err error) {
    var (
        file   *os.File
        client *storage.Client
        wc     *storage.Writer
    )

    defer func() {
        for _, c := range []io.Closer{wc, file} {
            if c != nil {
                err = c.Close()
                if err != nil {
                    return
                }
            }
        }
    }()

    file, err = os.Open(fromFile)
    if err != nil {
        err = fmt.Errorf("problem opening file %v: %v", fromFile, err)
        return
    }

    wc = client.Bucket(toBucket).Object(toPath).NewWriter(ctx)

    _, err = io.Copy(wc, file) // THE UNRECOVERABLE PANIC HAPPENS HERE

    return
}

恐慌是:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x9e0fa8]

goroutine 21 [running]:
cloud.google.com/go/storage.(*Writer).open.func1(0xc000161200, 0xc0002721e0, 0xc000150388, 0xc000290e20, 0x1, 0x1)
    C:/Users/xxxx/go/pkg/mod/cloud.google.com/go/storage@v1.14.0/writer.go:128 +0x248
created by cloud.google.com/go/storage.(*Writer).open
    C:/Users/xxxx/go/pkg/mod/cloud.google.com/go/storage@v1.14.0/writer.go:118 +0x6ce
Process exiting with code: 0
module main

go 1.15

require cloud.google.com/go/storage v1.14.0
go version go1.15.10 windows/amd64

关键是,如果它在其他地方发生恐慌,例如我指向一个无效文件,它会恐慌,并且延迟恢复会正确捕获它。

这让我很困惑。有什么想法吗?

正如您在上面的评论中看到的那样,答案是 cloud.google.com/go/storage 作者正在创建一个 goroutine,并将 panic 扔在那里。 GO 不允许你从另一个 goroutine 中恢复。