Can't recover from panic - defer is entirely skipped

-1

When using io.Copy with an invalid writer, I get a panic - that's expected. However I can't recover when this is the case. My deferred recover is completely bypassed. Here is the code:

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
}

The panic being:

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

The kicker is, if it panics elsewhere, for example I point to an invalid file, it'll panic, and the deferred recover properly captures it.

This has me baffled. Any idea?

go
recover
panic
asked on Stack Overflow Apr 6, 2021 by ymerej • edited Apr 6, 2021 by ymerej

1 Answer

0

The answer, as you can read in the comments above, is that cloud.google.com/go/storage writer is creating a goroutine, and throwing the panic in there. GO does not allow you to recover from another goroutine.

answered on Stack Overflow Apr 7, 2021 by ymerej

User contributions licensed under CC BY-SA 3.0