spf13 / afero

A FileSystem Abstraction System for Go
Apache License 2.0
5.79k stars 498 forks source link

MemMapFs MkdirAll error in parallel tests after go 1.18 #380

Open biinari opened 1 year ago

biinari commented 1 year ago

Creating a MemMapFs in a table driven test running in parallel can cause an internal compiler error.

Minimal reproduction test code:

func TestMkdirAll_fails(t *testing.T) {
    var tests = []struct {
        fs afero.Fs
    }{
        {
            fs: func() afero.Fs {
                fs := afero.NewMemMapFs()
                fs.MkdirAll("/home/alice", 0755)
                return fs
            }(),
        },
    }

    for _, tc := range tests {
        tc := tc // capture range variable
        t.Run("sub_test", func(t *testing.T) {
            _ = tc.fs
        })
    }
}

Produces the error:

./mkdirall_test.go:16:16: internal compiler error: order.stmt CALLMETH

Please file a bug report including a short program that triggers the error.
https://go.dev/issue/new

Versions

This works without error on golang 1.17.13. It fails for me on go 1.18.8 and go 1.19.3.

I have tried on an older afero 1.2.2 as well as the current afero 1.9.3 with the same results.

Workaround

A workaround is to make sure the fs is created inside the test Run() rather than in the declaration of the test cases. Such as:

func TestMkdirAll_ok(t *testing.T) {
    var tests = []struct {
        path     string
        createFs func() afero.Fs
    }{
        {
            createFs: func() afero.Fs {
                fs := afero.NewMemMapFs()
                fs.MkdirAll("/home/alice", 0755)
                return fs
            },
        },
    }

    for _, tc := range tests {
        tc := tc // capture range variable
        t.Run("sub_test", func(t *testing.T) {
            _ = tc.createFs()
        })
    }
}

To be honest, I'm not convinced my original code that was trying to share the fs between different goroutines was sensible. If this is not to be fixed, perhaps it would be worth mentioning in the readme that a MemMapFs cannot be passed between goroutines.