Files
rclone/vfs/vfscommon/recover_test.go
Nick Craig-Wood 208d7df877 vfs: don't crash the process if a backend panics on a background goroutine GHSA-6jcg-q3wp-x2f4
The VFS calls backends from goroutines of its own. A panic on any of these
cannot be recovered. So a backend panicking on a single file killed the whole
process, taking down a mount or every user of a serve command, even for servers
such as serve http whose library recovers panics raised on its own request
goroutines.

Recover panics at those goroutines and log them with a stack trace. Where the
surrounding code already handles a failure, recover around the backend call
itself rather than the whole goroutine, so a panicking upload is retried like
any other failed upload and a panicking download is reported to the waiters,
instead of abandoning the work part way through and leaving the bookkeeping
inconsistent.

Addresses GHSA-6jcg-q3wp-x2f4
2026-07-31 13:21:59 +01:00

42 lines
999 B
Go

package vfscommon
import (
"errors"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestRecoverPanic(t *testing.T) {
// Panic recovered into err
err := func() (err error) {
defer RecoverPanic("test", &err)
panic("boom")
}()
require.Error(t, err)
assert.ErrorContains(t, err, "boom")
// No panic leaves err alone
err = func() (err error) {
defer RecoverPanic("test", nil)
return nil
}()
assert.NoError(t, err)
// A nil error target is allowed, for goroutines with nothing to report to
assert.NotPanics(t, func() {
defer RecoverPanic("test", nil)
panic("boom")
})
}
func TestRecoverCall(t *testing.T) {
assert.ErrorContains(t, RecoverCall("test", func() error { panic("boom") }), "boom")
// Ordinary errors and results pass through untouched
errFoo := errors.New("foo")
assert.Equal(t, errFoo, RecoverCall("test", func() error { return errFoo }))
assert.NoError(t, RecoverCall("test", func() error { return nil }))
}