Repository: tetratelabs/wazero
Pull request #1565 (2023-07-06 14:56:45)

fs: empty guest path should bind to /
Fixes https://github.com/tetratelabs/wazero/issues/1564.

Commit https://github.com/tetratelabs/wazero/commit/53ce5eea830b3100af7ec8caa13bb38310c0afbf#diff-4fb3ce1d291b912fd6aa5e7f790040234a92683e313d1c757c0fce7be9e43320L397-L400 altered the effective behavior of `.WithFS()`; whereas prior to this patch a single, non-composite FS would always bind to "/" :

https://github.com/tetratelabs/wazero/blob/97d0d70b7321e5c16e584bbb6b3169032208bdec/internal/sys/fs.go#L469-L476

now, the `guestPath` is always used:

https://github.com/tetratelabs/wazero/blob/485b9e3ece346c2dd0912e1a54703d70fa10cdcf/internal/sys/fs.go#L420-L425

we resolve by overriding `guestPath` to `"/"` when `StripPrefixesAndTrailingSlash(guestPath) == ""`


Patch:
diff --git a/internal/sys/fs.go b/internal/sys/fs.go
index 2622ba77..7d1c1056 100644
--- a/internal/sys/fs.go
+++ b/internal/sys/fs.go
@@ -413,6 +413,8 @@ func (c *Context) InitFSContext(
 		guestPath := guestPaths[i]
 
 		if StripPrefixesAndTrailingSlash(guestPath) == "" {
+			// Default to bind to '/' when guestPath is effectively empty.
+			guestPath = "/"
 			c.fsc.rootFS = fs
 		}
 		c.fsc.openedFiles.Insert(&FileEntry{


Test patch:
diff --git a/internal/sys/fs_test.go b/internal/sys/fs_test.go
index 9824cdd7..0a199963 100644
--- a/internal/sys/fs_test.go
+++ b/internal/sys/fs_test.go
@@ -3,6 +3,7 @@ package sys
 import (
 	"embed"
 	"errors"
+	"fmt"
 	"io/fs"
 	"os"
 	"path"
@@ -55,36 +56,41 @@ func TestNewFSContext(t *testing.T) {
 		tc := tt
 
 		t.Run(tc.name, func(t *testing.T) {
-			c := Context{}
-			err := c.InitFSContext(nil, nil, nil, []fsapi.FS{tc.fs}, []string{"/"}, nil)
-			require.NoError(t, err)
-			fsc := c.fsc
-			defer fsc.Close()
-
-			preopenedDir, _ := fsc.openedFiles.Lookup(FdPreopen)
-			require.Equal(t, tc.fs, fsc.rootFS)
-			require.NotNil(t, preopenedDir)
-			require.Equal(t, "/", preopenedDir.Name)
-
-			// Verify that each call to OpenFile returns a different file
-			// descriptor.
-			f1, errno := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
-			require.EqualErrno(t, 0, errno)
-			require.NotEqual(t, FdPreopen, f1)
-
-			// Verify that file descriptors are reused.
-			//
-			// Note that this specific behavior is not required by WASI which
-			// only documents that file descriptor numbers will be selected
-			// randomly and applications should not rely on them. We added this
-			// test to ensure that our implementation properly reuses descriptor
-			// numbers but if we were to change the reuse strategy, this test
-			// would likely break and need to be updated.
-			require.EqualErrno(t, 0, fsc.CloseFile(f1))
-			f2, errno := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
-			require.EqualErrno(t, 0, errno)
-			require.Equal(t, f1, f2)
+			for _, root := range []string{"/", ""} {
+				t.Run(fmt.Sprintf("root = '%s'", root), func(t *testing.T) {
+					c := Context{}
+					err := c.InitFSContext(nil, nil, nil, []fsapi.FS{tc.fs}, []string{root}, nil)
+					require.NoError(t, err)
+					fsc := c.fsc
+					defer fsc.Close()
+
+					preopenedDir, _ := fsc.openedFiles.Lookup(FdPreopen)
+					require.Equal(t, tc.fs, fsc.rootFS)
+					require.NotNil(t, preopenedDir)
+					require.Equal(t, "/", preopenedDir.Name)
+
+					// Verify that each call to OpenFile returns a different file
+					// descriptor.
+					f1, errno := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
+					require.EqualErrno(t, 0, errno)
+					require.NotEqual(t, FdPreopen, f1)
+
+					// Verify that file descriptors are reused.
+					//
+					// Note that this specific behavior is not required by WASI which
+					// only documents that file descriptor numbers will be selected
+					// randomly and applications should not rely on them. We added this
+					// test to ensure that our implementation properly reuses descriptor
+					// numbers but if we were to change the reuse strategy, this test
+					// would likely break and need to be updated.
+					require.EqualErrno(t, 0, fsc.CloseFile(f1))
+					f2, errno := fsc.OpenFile(preopenedDir.FS, preopenedDir.Name, 0, 0)
+					require.EqualErrno(t, 0, errno)
+					require.Equal(t, f1, f2)
+				})
+			}
 		})
+
 	}
 }