mirror of
https://github.com/hanzoai/wasm2go.git
synced 2026-10-30 15:06:48 +00:00
* Trap memory64 scalar out-of-bounds/overflow before native pointer use: internal/codegen/emit_memops.go * Trap memory64 scalar out-of-bounds/overflow before native pointer use: internal/codegen/helpers/helpers.go * Regression: memory64 scalar loads/stores must trap on u64 overflow * Make greater-than-4GiB memory certification fail closed when required * Add required real >4 GiB Memory64 CI gate * Repair Memory64 CI workflow YAML after broken replacement * CLI: add strict -require-memory64 mode for native AOT builds * Test strict memory64 CLI accepts wasm64 and refuses wasm32 * Document strict Memory64 AOT mode and real 4 GiB proof requirements * Register memory64 bounds helper in generator dependency closure * Test memory64 bounds helper and keep extractor-only function referenced * Align compiler-source lint/vet with generated benchmark policy (Makefile) * Align compiler-source lint/vet with generated benchmark policy (internal/testfixture/fixture.go) * Correct Memory64 scalar boundary regression to actually test out-of-range address * Fix Go formatting of memory64 bounds test table * Fix escaped newline expectations in Memory64 scalar runtime regression * Fix trailing comma in Memory64 test composite literal
138 lines
3.7 KiB
Go
138 lines
3.7 KiB
Go
// Package testfixture compiles .wat test fixtures to wasm on demand.
|
|
// It is a non-test package so that any test binary in the module can import it.
|
|
package testfixture
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"sync"
|
|
"testing"
|
|
)
|
|
|
|
var (
|
|
cacheMu sync.Mutex
|
|
cache = map[string][]byte{}
|
|
watFlagsOnce sync.Once
|
|
watFlags []string
|
|
)
|
|
|
|
func getWatFlags() []string {
|
|
watFlagsOnce.Do(func() {
|
|
out, err := exec.Command("wat2wasm", "--help").CombinedOutput()
|
|
if err != nil {
|
|
// The later Wasm() invocation will report the real compiler
|
|
// failure. Do not infer unsupported flags from a broken help run.
|
|
return
|
|
}
|
|
help := string(out)
|
|
var flags []string
|
|
if strings.Contains(help, "--enable-exceptions") {
|
|
flags = append(flags, "--enable-exceptions")
|
|
}
|
|
if strings.Contains(help, "--enable-threads") {
|
|
flags = append(flags, "--enable-threads")
|
|
}
|
|
if strings.Contains(help, "--enable-memory64") {
|
|
flags = append(flags, "--enable-memory64")
|
|
}
|
|
watFlags = flags
|
|
})
|
|
return watFlags
|
|
}
|
|
|
|
// Wasm compiles testdata/<basename>.wat via wat2wasm and returns the wasm bytes.
|
|
// name may include or omit the .wasm or .wat extension — both are accepted and
|
|
// stripped to derive the bare basename.
|
|
// Results are cached per-process so each fixture is compiled at most once.
|
|
func Wasm(t testing.TB, name string) []byte {
|
|
t.Helper()
|
|
|
|
// Strip known extensions to get the bare basename.
|
|
base := name
|
|
if strings.HasSuffix(base, ".wasm") {
|
|
base = strings.TrimSuffix(base, ".wasm")
|
|
} else if strings.HasSuffix(base, ".wat") {
|
|
base = strings.TrimSuffix(base, ".wat")
|
|
}
|
|
|
|
cacheMu.Lock()
|
|
if data, ok := cache[base]; ok {
|
|
cacheMu.Unlock()
|
|
return data
|
|
}
|
|
cacheMu.Unlock()
|
|
|
|
root := repoRoot()
|
|
watPath := filepath.Join(root, "testdata", base+".wat")
|
|
if _, err := os.Stat(watPath); err != nil {
|
|
t.Fatalf("testfixture: wat source not found: %s", watPath)
|
|
}
|
|
|
|
args := append([]string{}, getWatFlags()...)
|
|
args = append(args, "--output=-", watPath)
|
|
cmd := exec.Command("wat2wasm", args...)
|
|
var stdout, stderr bytes.Buffer
|
|
cmd.Stdout = &stdout
|
|
cmd.Stderr = &stderr
|
|
if err := cmd.Run(); err != nil {
|
|
t.Fatalf("testfixture: wat2wasm %s: %v\n%s", base, err, stderr.String())
|
|
}
|
|
data := stdout.Bytes()
|
|
|
|
cacheMu.Lock()
|
|
cache[base] = data
|
|
cacheMu.Unlock()
|
|
|
|
return data
|
|
}
|
|
|
|
// WasmPath compiles testdata/<basename>.wat and writes the result to a
|
|
// temporary file whose path is returned. The file is owned by t.TempDir()
|
|
// and is cleaned up when the test ends. This is useful for tests that must
|
|
// hand a file path to an external binary (e.g. the wasm2go CLI).
|
|
func WasmPath(t testing.TB, name string) string {
|
|
t.Helper()
|
|
data := Wasm(t, name)
|
|
|
|
// Derive a clean basename for the temp-file name.
|
|
base := name
|
|
if strings.HasSuffix(base, ".wasm") {
|
|
base = strings.TrimSuffix(base, ".wasm")
|
|
} else if strings.HasSuffix(base, ".wat") {
|
|
base = strings.TrimSuffix(base, ".wat")
|
|
}
|
|
|
|
dir := t.TempDir()
|
|
p := filepath.Join(dir, base+".wasm")
|
|
if err := os.WriteFile(p, data, 0600); err != nil {
|
|
t.Fatalf("testfixture: write temp wasm %s: %v", base, err)
|
|
}
|
|
return p
|
|
}
|
|
|
|
// repoRoot locates the repository root by walking up from this source file
|
|
// until it finds a directory containing go.mod.
|
|
func repoRoot() string {
|
|
// runtime.Caller(0) gives the absolute path of this source file.
|
|
_, file, _, ok := runtime.Caller(0)
|
|
if !ok {
|
|
panic("testfixture: runtime.Caller failed")
|
|
}
|
|
dir := filepath.Dir(file)
|
|
for {
|
|
if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
|
|
return dir
|
|
}
|
|
parent := filepath.Dir(dir)
|
|
if parent == dir {
|
|
panic(fmt.Sprintf("testfixture: go.mod not found above %s", filepath.Dir(file)))
|
|
}
|
|
dir = parent
|
|
}
|
|
}
|