Repository: tetratelabs/wazero
Pull request #996 (2023-01-01 06:39:26)

Ensures 32-bit platforms build
Trivy builds with linux_386, so this adds a check to ensure we cover 386 arch even if it may or may not work in interpreter (definitely not in compiler)

See https://github.com/aquasecurity/trivy/pull/3355


Patch:
diff --git a/Makefile b/Makefile
index ef9bd269..db7b5359 100644
--- a/Makefile
+++ b/Makefile
@@ -213,6 +213,7 @@ format:
 .PHONY: check
 check:
 	@GOARCH=amd64 GOOS=dragonfly go build ./... # Check if the internal/platform can be built on compiler-unsupported platforms
+	@GOARCH=386 GOOS=linux go build ./... # Check if the internal/platform can be built on compiler-unsupported platforms
 	@$(MAKE) lint golangci_lint_goarch=arm64
 	@$(MAKE) lint golangci_lint_goarch=amd64
 	@$(MAKE) format
diff --git a/imports/wasi_snapshot_preview1/fs.go b/imports/wasi_snapshot_preview1/fs.go
index acc52f95..50fa306f 100644
--- a/imports/wasi_snapshot_preview1/fs.go
+++ b/imports/wasi_snapshot_preview1/fs.go
@@ -273,15 +273,15 @@ var blockFilestat = []byte{
 func writeFilestat(buf []byte, stat fs.FileInfo) {
 	filetype := getWasiFiletype(stat.Mode())
 	filesize := uint64(stat.Size())
-	atimeSec, atimeNsec, mtimeSec, mtimeNsec, ctimeSec, ctimeNsec := platform.StatTimes(stat)
+	atimeNsec, mtimeNsec, ctimeNsec := platform.StatTimes(stat)
 
 	// memory is re-used, so ensure the result is defaulted.
 	copy(buf, blockFilestat[:32])
 	buf[16] = filetype
-	le.PutUint64(buf[32:], filesize)                       // filesize
-	le.PutUint64(buf[40:], uint64(atimeSec*1e9+atimeNsec)) // atim
-	le.PutUint64(buf[48:], uint64(mtimeSec*1e9+mtimeNsec)) // mtim
-	le.PutUint64(buf[56:], uint64(ctimeSec*1e9+ctimeNsec)) // ctim
+	le.PutUint64(buf[32:], filesize)          // filesize
+	le.PutUint64(buf[40:], uint64(atimeNsec)) // atim
+	le.PutUint64(buf[48:], uint64(mtimeNsec)) // mtim
+	le.PutUint64(buf[56:], uint64(ctimeNsec)) // ctim
 }
 
 // fdFilestatSetSize is the WASI function named FdFilestatSetSizeName which
diff --git a/internal/gojs/fs.go b/internal/gojs/fs.go
index 55c341b3..85889ab5 100644
--- a/internal/gojs/fs.go
+++ b/internal/gojs/fs.go
@@ -166,10 +166,10 @@ func syscallFstat(fsc *internalsys.FSContext, fd uint32) (*jsSt, error) {
 		ret.isDir = stat.IsDir()
 		ret.mode = getJsMode(stat.Mode())
 		ret.size = stat.Size()
-		atimeSec, atimeNsec, mtimeSec, mtimeNsec, ctimeSec, ctimeNsec := platform.StatTimes(stat)
-		ret.atimeMs = atimeSec*1e3 + atimeNsec/1e6
-		ret.mtimeMs = mtimeSec*1e3 + mtimeNsec/1e6
-		ret.ctimeMs = ctimeSec*1e3 + ctimeNsec/1e6
+		atimeNsec, mtimeNsec, ctimeNsec := platform.StatTimes(stat)
+		ret.atimeMs = atimeNsec / 1e6
+		ret.mtimeMs = mtimeNsec / 1e6
+		ret.ctimeMs = ctimeNsec / 1e6
 		return ret, nil
 	}
 }
@@ -525,7 +525,7 @@ func (*jsfsUtimes) invoke(ctx context.Context, mod api.Module, args ...interface
 // syscallUtimes is like syscall.Utimes
 func syscallUtimes(mod api.Module, name string, atimeSec, mtimeSec int64) (interface{}, error) {
 	fsc := mod.(*wasm.CallContext).Sys.FS()
-	err := fsc.Utimes(name, atimeSec, 0, mtimeSec, 0)
+	err := fsc.Utimes(name, atimeSec*1e9, mtimeSec*1e9)
 	return err != nil, err
 }
 
diff --git a/internal/platform/stat.go b/internal/platform/stat.go
index 6fb76de2..603e811f 100644
--- a/internal/platform/stat.go
+++ b/internal/platform/stat.go
@@ -4,16 +4,16 @@ import "os"
 
 // StatTimes returns platform-specific values if os.FileInfo Sys is available.
 // Otherwise, it returns the mod time for all values.
-func StatTimes(t os.FileInfo) (atimeSec, atimeNsec, mtimeSec, mtimeNsec, ctimeSec, ctimeNsec int64) {
+func StatTimes(t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64) {
 	if t.Sys() == nil { // possibly fake filesystem
 		return mtimes(t)
 	}
 	return statTimes(t)
 }
 
-func mtimes(t os.FileInfo) (int64, int64, int64, int64, int64, int64) {
-	mtime := t.ModTime().UnixNano()
-	mtimeSec := mtime / 1e9
-	mtimeNsec := mtime % 1e9
-	return mtimeSec, mtimeNsec, mtimeSec, mtimeNsec, mtimeSec, mtimeNsec
+func mtimes(t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64) {
+	mtimeNsec = t.ModTime().UnixNano()
+	atimeNsec = mtimeNsec
+	ctimeNsec = mtimeNsec
+	return
 }
diff --git a/internal/platform/stat_bsd.go b/internal/platform/stat_bsd.go
index a3f70ca0..e9827e5a 100644
--- a/internal/platform/stat_bsd.go
+++ b/internal/platform/stat_bsd.go
@@ -1,4 +1,4 @@
-//go:build darwin || freebsd
+//go:build (amd64 || arm64) && (darwin || freebsd)
 
 package platform
 
@@ -7,10 +7,10 @@ import (
 	"syscall"
 )
 
-func statTimes(t os.FileInfo) (atimeSec, atimeNSec, mtimeSec, mtimeNSec, ctimeSec, ctimeNSec int64) {
+func statTimes(t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64) {
 	d := t.Sys().(*syscall.Stat_t)
 	atime := d.Atimespec
 	mtime := d.Mtimespec
 	ctime := d.Ctimespec
-	return atime.Sec, atime.Nsec, mtime.Sec, mtime.Nsec, ctime.Sec, ctime.Nsec
+	return atime.Sec*1e9 + atime.Nsec, mtime.Sec*1e9 + mtime.Nsec, ctime.Sec*1e9 + ctime.Nsec
 }
diff --git a/internal/platform/stat_linux.go b/internal/platform/stat_linux.go
index 1e00a5d7..aaaf253f 100644
--- a/internal/platform/stat_linux.go
+++ b/internal/platform/stat_linux.go
@@ -1,3 +1,5 @@
+//go:build (amd64 || arm64) && linux
+
 package platform
 
 import (
@@ -5,10 +7,10 @@ import (
 	"syscall"
 )
 
-func statTimes(t os.FileInfo) (atimeSec, atimeNSec, mtimeSec, mtimeNSec, ctimeSec, ctimeNSec int64) {
+func statTimes(t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64) {
 	d := t.Sys().(*syscall.Stat_t)
 	atime := d.Atim
 	mtime := d.Mtim
 	ctime := d.Ctim
-	return atime.Sec, atime.Nsec, mtime.Sec, mtime.Nsec, ctime.Sec, ctime.Nsec
+	return atime.Sec*1e9 + atime.Nsec, mtime.Sec*1e9 + mtime.Nsec, ctime.Sec*1e9 + ctime.Nsec
 }
diff --git a/internal/platform/stat_unsupported.go b/internal/platform/stat_unsupported.go
index 20807132..140549f8 100644
--- a/internal/platform/stat_unsupported.go
+++ b/internal/platform/stat_unsupported.go
@@ -1,9 +1,9 @@
-//go:build !(darwin || linux || freebsd || windows)
+//go:build !(amd64 || arm64) || !(darwin || linux || freebsd || windows)
 
 package platform
 
 import "os"
 
-func statTimes(t os.FileInfo) (atimeSec, atimeNSec, mtimeSec, mtimeNSec, ctimeSec, ctimeNSec int64) {
+func statTimes(t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64) {
 	return mtimes(t)
 }
diff --git a/internal/platform/stat_windows.go b/internal/platform/stat_windows.go
index 8dee4a23..5080d933 100644
--- a/internal/platform/stat_windows.go
+++ b/internal/platform/stat_windows.go
@@ -1,3 +1,5 @@
+//go:build (amd64 || arm64) && windows
+
 package platform
 
 import (
@@ -5,10 +7,10 @@ import (
 	"syscall"
 )
 
-func statTimes(t os.FileInfo) (atimeSec, atimeNsec, mtimeSec, mtimeNsec, ctimeSec, ctimeNsec int64) {
+func statTimes(t os.FileInfo) (atimeNsec, mtimeNsec, ctimeNsec int64) {
 	d := t.Sys().(*syscall.Win32FileAttributeData)
-	atime := d.LastAccessTime.Nanoseconds()
-	mtime := d.LastWriteTime.Nanoseconds()
-	ctime := d.CreationTime.Nanoseconds()
-	return atime / 1e9, atime % 1e9, mtime / 1e9, mtime % 1e9, ctime / 1e9, ctime % 1e9
+	atimeNsec = d.LastAccessTime.Nanoseconds()
+	mtimeNsec = d.LastWriteTime.Nanoseconds()
+	ctimeNsec = d.CreationTime.Nanoseconds()
+	return
 }
diff --git a/internal/sys/fs.go b/internal/sys/fs.go
index 27180422..deb5c8b3 100644
--- a/internal/sys/fs.go
+++ b/internal/sys/fs.go
@@ -368,10 +368,10 @@ func (c *FSContext) Unlink(name string) (err error) {
 }
 
 // Utimes is like syscall.Utimes.
-func (c *FSContext) Utimes(name string, atimeSec, atimeNsec, mtimeSec, mtimeNsec int64) (err error) {
+func (c *FSContext) Utimes(name string, atimeNsec, mtimeNsec int64) (err error) {
 	if wfs, ok := c.fs.(syscallfs.FS); ok {
 		name = c.cleanPath(name)
-		return wfs.Utimes(name, atimeSec, atimeNsec, mtimeSec, mtimeNsec)
+		return wfs.Utimes(name, atimeNsec, mtimeNsec)
 	}
 	err = syscall.ENOSYS
 	return
diff --git a/internal/syscallfs/dirfs.go b/internal/syscallfs/dirfs.go
index 5e4e0eac..ca6e1358 100644
--- a/internal/syscallfs/dirfs.go
+++ b/internal/syscallfs/dirfs.go
@@ -83,13 +83,12 @@ func (dir dirFS) Unlink(name string) error {
 }
 
 // Utimes implements FS.Utimes
-func (dir dirFS) Utimes(name string, atimeSec, atimeNsec, mtimeSec, mtimeNsec int64) error {
+func (dir dirFS) Utimes(name string, atimeNsec, mtimeNsec int64) error {
 	if !fs.ValidPath(name) {
 		return syscall.EINVAL
 	}
-
 	return syscall.UtimesNano(path.Join(string(dir), name), []syscall.Timespec{
-		{Sec: atimeSec, Nsec: atimeNsec},
-		{Sec: mtimeSec, Nsec: mtimeNsec},
+		syscall.NsecToTimespec(atimeNsec),
+		syscall.NsecToTimespec(mtimeNsec),
 	})
 }
diff --git a/internal/syscallfs/syscallfs.go b/internal/syscallfs/syscallfs.go
index 9c0eb6ba..05aaacb8 100644
--- a/internal/syscallfs/syscallfs.go
+++ b/internal/syscallfs/syscallfs.go
@@ -83,5 +83,5 @@ type FS interface {
 	//   - To set wall clock time, retrieve it first from sys.Walltime.
 	//   - syscall.UtimesNano cannot change the ctime. Also, neither WASI nor
 	//     runtime.GOOS=js support changing it. Hence, ctime it is absent here.
-	Utimes(path string, atimeSec, atimeNsec, mtimeSec, mtimeNsec int64) error
+	Utimes(path string, atimeNsec, mtimeNsec int64) error
 }


Test patch:
diff --git a/internal/platform/stat_test.go b/internal/platform/stat_test.go
index eafd326e..23f836fe 100644
--- a/internal/platform/stat_test.go
+++ b/internal/platform/stat_test.go
@@ -18,38 +18,44 @@ func Test_StatTimes(t *testing.T) {
 	require.NoError(t, err)
 
 	type test struct {
-		name                                     string
-		atimeSec, atimeNsec, mtimeSec, mtimeNsec int64
+		name                 string
+		atimeNsec, mtimeNsec int64
 	}
 	// Note: This sets microsecond granularity because Windows doesn't support
 	// nanosecond.
 	tests := []test{
-		{name: "positive", atimeSec: 123, atimeNsec: 4 * 1e3, mtimeSec: 567, mtimeNsec: 8 * 1e3},
+		{
+			name:      "positive",
+			atimeNsec: time.Unix(123, 4*1e3).UnixNano(),
+			mtimeNsec: time.Unix(567, 8*1e3).UnixNano(),
+		},
 		{name: "zero"},
 	}
 
 	// linux and freebsd report inaccurate results when the input ts is negative.
 	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
 		tests = append(tests,
-			test{name: "negative", atimeSec: -123, atimeNsec: -4 * 1e3, mtimeSec: -567, mtimeNsec: -8 * 1e3},
+			test{
+				name:      "negative",
+				atimeNsec: time.Unix(-123, -4*1e3).UnixNano(),
+				mtimeNsec: time.Unix(-567, -8*1e3).UnixNano(),
+			},
 		)
 	}
 
 	for _, tt := range tests {
 		tc := tt
 		t.Run(tc.name, func(t *testing.T) {
-			err := os.Chtimes(file, time.Unix(tc.atimeSec, tc.atimeNsec), time.Unix(tc.mtimeSec, tc.mtimeNsec))
+			err := os.Chtimes(file, time.UnixMicro(tc.atimeNsec/1e3), time.UnixMicro(tc.mtimeNsec/1e3))
 			require.NoError(t, err)
 
 			stat, err := os.Stat(file)
 			require.NoError(t, err)
 
-			atimeSec, atimeNsec, mtimeSec, mtimeNsec, _, _ := StatTimes(stat)
+			atimeNsec, mtimeNsec, _ := StatTimes(stat)
 			if CompilerSupported() {
-				require.Equal(t, atimeSec, tc.atimeSec)
 				require.Equal(t, atimeNsec, tc.atimeNsec)
 			} // else only mtimes will return.
-			require.Equal(t, mtimeSec, tc.mtimeSec)
 			require.Equal(t, mtimeNsec, tc.mtimeNsec)
 		})
 	}
diff --git a/internal/syscallfs/dirfs_test.go b/internal/syscallfs/dirfs_test.go
index 8b782155..e002136e 100644
--- a/internal/syscallfs/dirfs_test.go
+++ b/internal/syscallfs/dirfs_test.go
@@ -8,6 +8,7 @@ import (
 	"runtime"
 	"syscall"
 	"testing"
+	"time"
 
 	"github.com/tetratelabs/wazero/internal/platform"
 	"github.com/tetratelabs/wazero/internal/testing/require"
@@ -327,21 +328,33 @@ func TestDirFS_Utimes(t *testing.T) {
 	require.NoError(t, err)
 
 	t.Run("doesn't exist", func(t *testing.T) {
-		err := testFS.Utimes("nope", 123, 4, 567, 8)
+		err := testFS.Utimes("nope",
+			time.Unix(123, 4*1e3).UnixNano(),
+			time.Unix(567, 8*1e3).UnixNano())
 		require.Equal(t, syscall.ENOENT, err)
 	})
 
 	type test struct {
-		name                                     string
-		path                                     string
-		atimeSec, atimeNsec, mtimeSec, mtimeNsec int64
+		name                 string
+		path                 string
+		atimeNsec, mtimeNsec int64
 	}
 
 	// Note: This sets microsecond granularity because Windows doesn't support
 	// nanosecond.
 	tests := []test{
-		{name: "file positive", path: file, atimeSec: 123, atimeNsec: 4 * 1e3, mtimeSec: 567, mtimeNsec: 8 * 1e3},
-		{name: "dir positive", path: dir, atimeSec: 123, atimeNsec: 4 * 1e3, mtimeSec: 567, mtimeNsec: 8 * 1e3},
+		{
+			name:      "file positive",
+			path:      file,
+			atimeNsec: time.Unix(123, 4*1e3).UnixNano(),
+			mtimeNsec: time.Unix(567, 8*1e3).UnixNano(),
+		},
+		{
+			name:      "dir positive",
+			path:      dir,
+			atimeNsec: time.Unix(123, 4*1e3).UnixNano(),
+			mtimeNsec: time.Unix(567, 8*1e3).UnixNano(),
+		},
 		{name: "file zero", path: file},
 		{name: "dir zero", path: dir},
 	}
@@ -349,26 +362,34 @@ func TestDirFS_Utimes(t *testing.T) {
 	// linux and freebsd report inaccurate results when the input ts is negative.
 	if runtime.GOOS == "windows" || runtime.GOOS == "darwin" {
 		tests = append(tests,
-			test{name: "file negative", path: file, atimeSec: -123, atimeNsec: -4 * 1e3, mtimeSec: -567, mtimeNsec: -8 * 1e3},
-			test{name: "dir negative", path: dir, atimeSec: -123, atimeNsec: -4 * 1e3, mtimeSec: -567, mtimeNsec: -8 * 1e3},
+			test{
+				name:      "file negative",
+				path:      file,
+				atimeNsec: time.Unix(-123, -4*1e3).UnixNano(),
+				mtimeNsec: time.Unix(-567, -8*1e3).UnixNano(),
+			},
+			test{
+				name:      "dir negative",
+				path:      dir,
+				atimeNsec: time.Unix(-123, -4*1e3).UnixNano(),
+				mtimeNsec: time.Unix(-567, -8*1e3).UnixNano(),
+			},
 		)
 	}
 
 	for _, tt := range tests {
 		tc := tt
 		t.Run(tc.name, func(t *testing.T) {
-			err := testFS.Utimes(tc.path, tc.atimeSec, tc.atimeNsec, tc.mtimeSec, tc.mtimeNsec)
+			err := testFS.Utimes(tc.path, tc.atimeNsec, tc.mtimeNsec)
 			require.NoError(t, err)
 
 			stat, err := os.Stat(path.Join(tmpDir, tc.path))
 			require.NoError(t, err)
 
-			atimeSec, atimeNsec, mtimeSec, mtimeNsec, _, _ := platform.StatTimes(stat)
+			atimeNsec, mtimeNsec, _ := platform.StatTimes(stat)
 			if platform.CompilerSupported() {
-				require.Equal(t, atimeSec, tc.atimeSec)
 				require.Equal(t, atimeNsec, tc.atimeNsec)
 			} // else only mtimes will return.
-			require.Equal(t, mtimeSec, tc.mtimeSec)
 			require.Equal(t, mtimeNsec, tc.mtimeNsec)
 		})
 	}